diff --git a/web/chat/chat-thread-list-item.react.js b/web/chat/chat-thread-list-item.react.js index 978de4012..ebdbcdba7 100644 --- a/web/chat/chat-thread-list-item.react.js +++ b/web/chat/chat-thread-list-item.react.js @@ -1,182 +1,179 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import type { ChatThreadItem } from 'lib/selectors/chat-selectors'; import { useAncestorThreads } from 'lib/shared/ancestor-threads'; import { shortAbsoluteDate } from 'lib/utils/date-utils'; import { useSelector } from '../redux/redux-utils'; import { useOnClickThread, useThreadIsActive, } from '../selectors/nav-selectors'; import SWMansionIcon from '../SWMansionIcon.react'; import ChatThreadListItemMenu from './chat-thread-list-item-menu.react'; import ChatThreadListSeeMoreSidebars from './chat-thread-list-see-more-sidebars.react'; import ChatThreadListSidebar from './chat-thread-list-sidebar.react'; import css from './chat-thread-list.css'; import MessagePreview from './message-preview.react'; type Props = { +item: ChatThreadItem, }; function ChatThreadListItem(props: Props): React.Node { const { item } = props; const { threadInfo, lastUpdatedTimeIncludingSidebars, mostRecentNonLocalMessage, mostRecentMessageInfo, } = item; const { id: threadID, currentUser } = threadInfo; const ancestorThreads = useAncestorThreads(threadInfo); const timeZone = useSelector(state => state.timeZone); const lastActivity = shortAbsoluteDate( lastUpdatedTimeIncludingSidebars, timeZone, ); const active = useThreadIsActive(threadID); const isCreateMode = useSelector( state => state.navInfo.chatMode === 'create', ); const onClick = useOnClickThread(item.threadInfo); const selectItemIfNotActiveCreation = React.useCallback( (event: SyntheticEvent) => { if (!isCreateMode || !active) { onClick(event); } }, [isCreateMode, active, onClick], ); const containerClassName = React.useMemo( () => classNames({ [css.thread]: true, [css.activeThread]: active, }), [active], ); const { unread } = currentUser; const titleClassName = React.useMemo( () => classNames({ [css.title]: true, [css.unread]: unread, }), [unread], ); const lastActivityClassName = React.useMemo( () => classNames({ [css.lastActivity]: true, [css.unread]: unread, [css.dark]: !unread, }), [unread], ); const breadCrumbsClassName = React.useMemo( () => classNames(css.breadCrumbs, { [css.unread]: unread, }), [unread], ); let unreadDot; if (unread) { unreadDot =
; } const { color } = item.threadInfo; const colorSplotchStyle = React.useMemo( () => ({ backgroundColor: `#${color}` }), [color], ); const sidebars = item.sidebars.map((sidebarItem, index) => { if (sidebarItem.type === 'sidebar') { const { type, ...sidebarInfo } = sidebarItem; return ( 0} key={sidebarInfo.threadInfo.id} /> ); } else if (sidebarItem.type === 'seeMore') { return ( ); } else { return
; } }); const ancestorPath = ancestorThreads.map((thread, idx) => { const isNotLast = idx !== ancestorThreads.length - 1; const chevron = isNotLast && ( ); return ( {thread.uiName} {chevron} ); }); return ( <> -
+
{unreadDot}

{ancestorPath}

{threadInfo.uiName}
{lastActivity}
-
+
{sidebars} ); } export default ChatThreadListItem; diff --git a/web/chat/chat-thread-list-see-more-sidebars.react.js b/web/chat/chat-thread-list-see-more-sidebars.react.js index 639b1937f..f0e5ece73 100644 --- a/web/chat/chat-thread-list-see-more-sidebars.react.js +++ b/web/chat/chat-thread-list-see-more-sidebars.react.js @@ -1,50 +1,50 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import { IoIosMore } from 'react-icons/io'; import { useModalContext } from 'lib/components/modal-provider.react'; import type { ThreadInfo } from 'lib/types/thread-types'; import SidebarsModal from '../modals/threads/sidebars/sidebars-modal.react'; import css from './chat-thread-list.css'; type Props = { +threadInfo: ThreadInfo, +unread: boolean, }; function ChatThreadListSeeMoreSidebars(props: Props): React.Node { const { unread, threadInfo } = props; const { pushModal, popModal } = useModalContext(); const onClick = React.useCallback( () => pushModal( , ), [popModal, pushModal, threadInfo.id], ); return ( - + ); } export default ChatThreadListSeeMoreSidebars; diff --git a/web/chat/chat-thread-list-sidebar.react.js b/web/chat/chat-thread-list-sidebar.react.js index 058c2a1ed..9722b0696 100644 --- a/web/chat/chat-thread-list-sidebar.react.js +++ b/web/chat/chat-thread-list-sidebar.react.js @@ -1,53 +1,53 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import type { SidebarInfo } from 'lib/types/thread-types'; import { useOnClickThread, useThreadIsActive, } from '../selectors/nav-selectors'; import ChatThreadListItemMenu from './chat-thread-list-item-menu.react'; import css from './chat-thread-list.css'; import SidebarItem from './sidebar-item.react'; type Props = { +sidebarInfo: SidebarInfo, +isSubsequentItem: boolean, }; function ChatThreadListSidebar(props: Props): React.Node { const { sidebarInfo, isSubsequentItem } = props; const { threadInfo, mostRecentNonLocalMessage } = sidebarInfo; const { currentUser: { unread }, id: threadID, } = threadInfo; const active = useThreadIsActive(threadID); const onClick = useOnClickThread(threadInfo); let unreadDot; if (unread) { unreadDot =
; } return ( -
{unreadDot}
-
+ ); } export default ChatThreadListSidebar; diff --git a/web/chat/chat-thread-list.css b/web/chat/chat-thread-list.css index cc9fca93f..8355a80b4 100644 --- a/web/chat/chat-thread-list.css +++ b/web/chat/chat-thread-list.css @@ -1,294 +1,297 @@ -div.thread { +.thread { display: flex; flex-direction: row; } -div.threadListSidebar { +.threadListSidebar { display: flex; flex-direction: row; height: 32px; padding-right: 8px; position: relative; cursor: pointer; } -div.threadListSidebar > svg { +.threadListSidebar > svg { position: absolute; top: -7px; left: 30px; } -div.thread:first-child { +.thread:first-child { padding-top: 6px; } -div.activeThread, -div.threadListSidebar:hover { + +.activeThread, +.threadListSidebar:hover { background: var(--thread-active-bg); } -div.activeThread :is(div.dark, .lastMessage span.read, .title) { +.activeThread :is(div.dark, .lastMessage span.read, .title) { color: var(--chat-thread-list-color-active); } -div.activeThread .lastMessage.read { +.activeThread .lastMessage.read { color: var(--chat-thread-list-color-active); } -div.activeThread.thread:hover { +.activeThread.thread:hover { background: var(--thread-active-bg); } -div.thread:hover { + +.thread:hover { background: var(--thread-hover-bg); } + div.title { flex: 1; font-size: var(--m-font-16); font-weight: var(--semi-bold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--thread-color-read); line-height: var(--line-height-text); } .threadButton { flex: 1; cursor: pointer; overflow: hidden; padding-left: 12px; } .threadButton + div { display: flex; flex-direction: column; } .threadButtonSidebar { cursor: pointer; overflow: hidden; display: flex; align-items: center; padding-left: 12px; } p.breadCrumbs { display: flex; padding: 8px 0 2px 0; font-size: var(--xs-font-12); font-weight: var(--normal); color: var(--breadcrumb-color); } p.breadCrumbs.unread { color: var(--breadcrumb-color-unread); } span.breadCrumb { display: flex; align-items: center; white-space: nowrap; text-overflow: ellipsis; } span.breadCrumb svg { margin-left: 4px; margin-right: 4px; } div.colorContainer { display: flex; padding-top: 8px; } div.spacer, div.colorSplotch { width: 42px; border-radius: 1.68px; } div.colorSplotchContainer { height: 42px; display: flex; } div.lastActivity { font-size: var(--xxs-font-10); color: var(--fg); line-height: 1.5; padding-right: 16px; font-weight: var(--semi-bold); white-space: nowrap; flex-grow: 1; padding-bottom: 12px; align-items: flex-end; display: flex; } div.lastMessage { font-size: 16px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: var(--line-height-text); padding-bottom: 8px; } div.threadRow > .lastMessage { color: var(--thread-last-message-color-read); font-size: var(--s-font-14); } div.unread { color: var(--fg); font-weight: var(--semi-bold); } div.lastMessage.unread { color: var(--fg); } div.dark { color: var(--thread-color-read); padding-right: 16px; } .read { color: var(--thread-from-color-read); } div.dotContainer { display: flex; align-items: center; justify-content: center; width: 16px; } div.unreadDot { height: 4px; width: 4px; background: var(--fg); border-radius: 15px; align-self: center; } div.italic { font-style: italic; } div.sidebarTitle { flex: 1; font-size: var(--s-font-14); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--thread-color-read); align-self: flex-start; } -div.threadListSidebar > div.dotContainer { +.threadListSidebar > div.dotContainer { width: 16px; } div.sidebarTitle.unread { color: var(--fg); } div.seeMoreButton { display: flex; align-items: center; padding-left: 22px; } div.seeMoreText { padding-left: 14px; } div.sidebarLastActivity { white-space: nowrap; font-size: var(--xxs-font-10); line-height: var(--line-height-text); font-weight: var(--semi-bold); } svg.sidebarIcon { color: var(--thread-color-read); padding: 0 6px; font-size: 20px; } div.sidebar .menu > button svg { font-size: 16px; color: var(--thread-color-read); } div.sidebar .menu { opacity: 0; } div.sidebar:hover .menu { display: flex; align-self: flex-end; opacity: 1; } .menu { position: relative; display: flex; justify-content: flex-end; } .menu > button { background-color: transparent; color: var(--thread-color-read); border: none; cursor: pointer; display: flex; align-items: center; } .menu > button:focus { outline: none; } .menuContent { display: none; position: absolute; top: calc(100% + 1px); right: 0; z-index: 1; width: max-content; overflow: hidden; background-color: #eeeeee; border-radius: 5px; box-shadow: 1px 1px 5px 2px #00000022; } .menuContentVisible { display: block; } button.menuContent { border: none; cursor: pointer; padding: 10px; font-size: 16px; } button.menuContent:hover { background-color: #dddddd; } ul.list { margin: 5px 3px 10px 0; overflow: auto; } div.spacer { height: 6px; } div.emptyItemContainer { display: flex; flex-direction: column; align-items: center; } div.emptyItemText { padding: 16px; font-size: 16px; text-align: center; white-space: pre-wrap; color: var(--fg); } div.threadListContainer { display: flex; flex-direction: column; overflow: auto; } div.createNewThread { display: flex; flex-direction: column; align-items: stretch; padding: 8px; } img.longArrow { height: 40px; width: 25px; position: absolute; left: 28.5px; top: -18px; } img.arrow { position: absolute; left: 28px; top: -10px; } diff --git a/web/chat/inline-sidebar.css b/web/chat/inline-sidebar.css index 56a1fae24..2c7d04195 100644 --- a/web/chat/inline-sidebar.css +++ b/web/chat/inline-sidebar.css @@ -1,57 +1,57 @@ div.inlineSidebarContainer { display: flex; } div.centerContainer { justify-content: center; } div.leftContainer { justify-content: flex-start; position: relative; top: -10px; left: 12px; margin-right: 12px; } div.rightContainer { justify-content: flex-end; position: relative; top: -10px; right: 31px; margin-left: 31px; } -div.inlineSidebarContent { +.inlineSidebarContent { background: var(--inline-sidebar-bg); color: var(--inline-sidebar-color); font-size: var(--s-font-14); line-height: var(--line-height-text); flex-direction: row; display: flex; border-radius: 16px; padding: 8px; cursor: pointer; gap: 12px; align-items: center; transition: background 0.2s ease-in-out; } -div.inlineSidebarContent:hover { +.inlineSidebarContent:hover { background: var(--inline-sidebar-bg-hover); } div.reactionsContainer { flex-direction: row; display: flex; gap: 4px; } div.replies { flex-direction: row; display: flex; align-items: center; gap: 4px; } div.unread { font-weight: bold; } svg.inlineSidebarIcon { color: #666666; } diff --git a/web/chat/inline-sidebar.react.js b/web/chat/inline-sidebar.react.js index c2072905b..c3b84ab7a 100644 --- a/web/chat/inline-sidebar.react.js +++ b/web/chat/inline-sidebar.react.js @@ -1,75 +1,75 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import useInlineSidebarText from 'lib/hooks/inline-sidebar-text.react'; import type { ThreadInfo } from 'lib/types/thread-types'; import CommIcon from '../CommIcon.react'; import { useOnClickThread } from '../selectors/nav-selectors'; import css from './inline-sidebar.css'; type Props = { +threadInfo: ?ThreadInfo, +reactions?: $ReadOnlyArray, +positioning: 'left' | 'center' | 'right', }; function InlineSidebar(props: Props): React.Node { const { threadInfo, positioning, reactions } = props; const inlineSidebarText = useInlineSidebarText(threadInfo); const containerClasses = classNames([ css.inlineSidebarContainer, { [css.leftContainer]: positioning === 'left', [css.centerContainer]: positioning === 'center', [css.rightContainer]: positioning === 'right', }, ]); const reactionsList = React.useMemo(() => { if (!reactions || reactions.length === 0) { return null; } const reactionsItems = reactions.map(reaction => { return (
{reaction}
); }); return
{reactionsItems}
; }, [reactions]); const onClick = useOnClickThread(threadInfo); const threadInfoExists = !!threadInfo; const sidebarItem = React.useMemo(() => { if (!threadInfoExists || !inlineSidebarText) { return null; } return (
{inlineSidebarText.repliesText}
); }, [threadInfoExists, inlineSidebarText]); return (
-
{sidebarItem} {reactionsList} -
+
); } export default InlineSidebar; diff --git a/web/components/button.css b/web/components/button.css index 1d01f1597..0b631348f 100644 --- a/web/components/button.css +++ b/web/components/button.css @@ -1,80 +1,72 @@ .btn { --border-width: 1px; --border-radius: 4px; position: relative; display: flex; flex-direction: row; align-items: center; justify-content: center; border: var(--border-width) solid transparent; font-size: var(--m-font-16); padding: 12px 24px; color: var(--fg); border-radius: var(--border-radius); cursor: pointer; } .btn.outline { border: var(--border-width) solid var(--btn-outline-border); } .btn > * { position: relative; } .btn::before { content: ''; border: inherit; border-radius: inherit; background: inherit; position: absolute; top: calc(-1 * var(--border-width)); left: calc(-1 * var(--border-width)); width: 100%; height: 100%; } .btn.outline::before { top: 0; left: 0; border: none; border-radius: calc(var(--border-radius) - var(--border-width)); } .btn:hover::before { transition-duration: 200ms; transition-property: filter; } .btn:hover:not(:disabled)::before { filter: brightness(0.8); } .btn.outline:hover:not(:disabled)::before { filter: brightness(2); } .btn:disabled { cursor: not-allowed; color: var(--btn-disabled-color); } .btn:not(.outline):disabled::before { background-color: var(--btn-bg-disabled); } -.round { - background: var(--settings-btn-bg); - width: 30px; - height: 30px; - border-radius: 50%; - padding: 0; -} - .text { background: transparent; white-space: nowrap; padding: 0; border: none; } diff --git a/web/components/button.react.js b/web/components/button.react.js index 89087e84f..7abf01a0b 100644 --- a/web/components/button.react.js +++ b/web/components/button.react.js @@ -1,81 +1,81 @@ // @flow import classnames from 'classnames'; import * as React from 'react'; import css from './button.css'; -export type ButtonVariant = 'filled' | 'outline' | 'round' | 'text'; +export type ButtonVariant = 'filled' | 'outline' | 'text'; export type ButtonColor = { +backgroundColor?: string, +color?: string, }; export const buttonThemes: { [string]: ButtonColor } = { standard: { backgroundColor: 'var(--btn-bg-filled)', }, danger: { backgroundColor: 'var(--btn-bg-danger)', }, success: { backgroundColor: 'var(--btn-bg-success)', }, outline: { backgroundColor: 'var(--btn-bg-outline)', }, }; export type ButtonProps = { +onClick: (event: SyntheticEvent) => mixed, +children: React.Node, +variant?: ButtonVariant, +buttonColor?: ButtonColor, +type?: string, +disabled?: boolean, +className?: string, }; function Button(props: ButtonProps): React.Node { const { onClick, children, variant = 'filled', buttonColor, type, disabled = false, className = '', } = props; const btnCls = classnames(css.btn, css[variant]); let style = {}; if (buttonColor) { style = buttonColor; } else if (variant === 'outline') { style = buttonThemes.outline; - } else if (variant === 'filled' || variant === 'round') { + } else if (variant === 'filled') { style = buttonThemes.standard; } const wrappedChildren = React.Children.map(children, child => { if (typeof child === 'string' || typeof child === 'number') { return {child}; } return child; }); return ( ); } export default Button; diff --git a/web/sidebar/app-switcher.react.js b/web/sidebar/app-switcher.react.js index b60352643..d727701e7 100644 --- a/web/sidebar/app-switcher.react.js +++ b/web/sidebar/app-switcher.react.js @@ -1,134 +1,134 @@ // @flow import * as React from 'react'; import { useDispatch } from 'react-redux'; import { mostRecentlyReadThreadSelector, unreadCount, } from 'lib/selectors/thread-selectors'; import { updateNavInfoActionType } from '../redux/action-types'; import { useSelector } from '../redux/redux-utils'; import { navTabSelector } from '../selectors/nav-selectors.js'; import SWMansionIcon from '../SWMansionIcon.react'; import css from './left-layout-aside.css'; import NavigationPanel from './navigation-panel.react'; function AppSwitcher(): React.Node { const activeChatThreadID = useSelector( state => state.navInfo.activeChatThreadID, ); const mostRecentlyReadThread = useSelector(mostRecentlyReadThreadSelector); const isActiveThreadCurrentlyUnread = useSelector( state => !activeChatThreadID || !!state.threadStore.threadInfos[activeChatThreadID]?.currentUser.unread, ); const dispatch = useDispatch(); const onClickChat = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatch({ type: updateNavInfoActionType, payload: { tab: 'chat', activeChatThreadID: isActiveThreadCurrentlyUnread ? mostRecentlyReadThread : activeChatThreadID, }, }); }, [ dispatch, isActiveThreadCurrentlyUnread, mostRecentlyReadThread, activeChatThreadID, ], ); const boundUnreadCount = useSelector(unreadCount); let chatBadge = null; if (boundUnreadCount > 0) { chatBadge = {boundUnreadCount}; } const chatNavigationItem = React.useMemo( () => ( - + ), [chatBadge, onClickChat], ); const onClickCalendar = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatch({ type: updateNavInfoActionType, payload: { tab: 'calendar' }, }); }, [dispatch], ); const isCalendarEnabled = useSelector(state => state.enabledApps.calendar); const calendarNavigationItem = React.useMemo(() => { if (!isCalendarEnabled) { return null; } return ( - + ); }, [isCalendarEnabled, onClickCalendar]); const onClickApps = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatch({ type: updateNavInfoActionType, payload: { tab: 'apps', }, }); }, [dispatch], ); const appNavigationItem = React.useMemo( () => ( - + ), [onClickApps], ); return ( {chatNavigationItem} {calendarNavigationItem} {appNavigationItem} ); } export default AppSwitcher; diff --git a/web/sidebar/community-picker.css b/web/sidebar/community-picker.css index 03a352cdc..777ac72bc 100644 --- a/web/sidebar/community-picker.css +++ b/web/sidebar/community-picker.css @@ -1,32 +1,42 @@ .container { display: flex; flex-direction: column; align-items: center; width: 84px; background: var(--community-bg); padding: 24px 0 32px 0; border-right: 1px solid var(--border-color); flex-grow: 1; } .spacer { flex-grow: 1; } .container button { color: var(--fg); } .container svg { color: var(--fg); padding: 0; } .activeContainer { display: flex; justify-content: center; width: 100%; box-sizing: border-box; border-left: 8px solid var(--community-settings-selected); border-right: 8px solid transparent; } + +.settingsIcon { + display: flex; + align-items: center; + justify-content: center; + background: var(--settings-btn-bg); + width: 30px; + height: 30px; + border-radius: 50%; +} diff --git a/web/sidebar/community-picker.react.js b/web/sidebar/community-picker.react.js index add1366f2..c0c8681f1 100644 --- a/web/sidebar/community-picker.react.js +++ b/web/sidebar/community-picker.react.js @@ -1,66 +1,65 @@ // @flow import classNames from 'classnames'; import * as React from 'react'; import { useDispatch } from 'react-redux'; -import Button from '../components/button.react'; import { updateNavInfoActionType } from '../redux/action-types.js'; import { useSelector } from '../redux/redux-utils.js'; import SWMansionIcon from '../SWMansionIcon.react'; import css from './community-picker.css'; function CommunityPicker(): React.Node { const dispatch = useDispatch(); const openAccountSettings = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatch({ type: updateNavInfoActionType, payload: { tab: 'settings', settingsSection: 'account' }, }); }, [dispatch], ); const isSettingsOpen = useSelector(state => state.navInfo.tab === 'settings'); const settingsButtonContainerClass = classNames({ [css.activeContainer]: isSettingsOpen, }); const openChat = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatch({ type: updateNavInfoActionType, payload: { tab: 'chat' }, }); }, [dispatch], ); const isInboxOpen = useSelector( state => state.navInfo.tab === 'chat' || state.navInfo.tab === 'apps' || state.navInfo.tab === 'calendar', ); const inboxButtonContainerClass = classNames({ [css.activeContainer]: isInboxOpen, }); return (
); } export default CommunityPicker; diff --git a/web/sidebar/left-layout-aside.css b/web/sidebar/left-layout-aside.css index 5ac7bfd45..4c79fa91b 100644 --- a/web/sidebar/left-layout-aside.css +++ b/web/sidebar/left-layout-aside.css @@ -1,70 +1,70 @@ .container { grid-area: sBar; background: var(--bg); color: var(--fg); border-right: 1px solid var(--border-color); display: flex; } .navigationPanelContainer { width: 160px; margin-top: 12px; } -div.navigationPanelTab { +.navigationPanelTab { display: flex; flex-direction: row; padding: 12px 0 12px 28px; cursor: pointer; } -div.navigationPanelTab svg { +.navigationPanelTab svg { padding-right: 12px; color: var(--color-disabled); stroke: var(--color-disabled); fill: var(--color-disabled); } -div.navigationPanelTab p { +.navigationPanelTab p { color: var(--color-disabled); } -div.navigationPanelTab:hover p, -div.navigationPanelTab:hover svg, +.navigationPanelTab:hover p, +.navigationPanelTab:hover svg, div.current_tab p, div.current_tab svg { color: var(--fg); stroke: var(--fg); fill: var(--fg); } .container p { display: flex; align-content: center; } .container svg { color: var(--color-disabled); padding-right: 12px; } .chatIconWrapper { position: relative; } span.chatBadge { position: absolute; top: -4px; left: 13px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 16px; height: 16px; color: var(--fg); background: var(--unread-bg); border-radius: 13px; font-size: 8px; line-height: 1.25; } diff --git a/web/sidebar/settings-switcher.react.js b/web/sidebar/settings-switcher.react.js index c831f1657..5f2442db9 100644 --- a/web/sidebar/settings-switcher.react.js +++ b/web/sidebar/settings-switcher.react.js @@ -1,64 +1,64 @@ // @flow import * as React from 'react'; import { useDispatch } from 'react-redux'; import { updateNavInfoActionType } from '../redux/action-types'; import { navSettingsSectionSelector } from '../selectors/nav-selectors.js'; import css from './left-layout-aside.css'; import NavigationPanel from './navigation-panel.react'; function SettingsSwitcher(): React.Node { const dispatch = useDispatch(); const onClickAccountSettings = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatch({ type: updateNavInfoActionType, payload: { tab: 'settings', settingsSection: 'account' }, }); }, [dispatch], ); const accountSettingsNavigationItem = React.useMemo( () => ( - + ), [onClickAccountSettings], ); const onClickDangerZone = React.useCallback( (event: SyntheticEvent) => { event.preventDefault(); dispatch({ type: updateNavInfoActionType, payload: { tab: 'settings', settingsSection: 'danger-zone' }, }); }, [dispatch], ); const dangerZoneNavigationItem = React.useMemo( () => ( - + ), [onClickDangerZone], ); return ( {accountSettingsNavigationItem} {dangerZoneNavigationItem} ); } export default SettingsSwitcher;