// Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { Key } from 'react'; import React from 'react'; import { Tabs, TabList, Tab, TabPanels, TabPanel } from 'react-aria-components'; import classNames from 'classnames'; import { Avatar, AvatarSize } from './Avatar'; import type { LocalizerType, ThemeType } from '../types/Util'; import type { ConversationType } from '../state/ducks/conversations'; import type { BadgeType } from '../badges/types'; import { NavTab } from '../state/ducks/nav'; import { Tooltip, TooltipPlacement } from './Tooltip'; import { Theme } from '../util/theme'; import type { UnreadStats } from '../util/countUnreadStats'; import { ContextMenu } from './ContextMenu'; type NavTabsItemBadgesProps = Readonly<{ i18n: LocalizerType; hasError?: boolean; hasPendingUpdate?: boolean; unreadStats: UnreadStats | null; }>; function NavTabsItemBadges({ i18n, hasError, hasPendingUpdate, unreadStats, }: NavTabsItemBadgesProps) { if (hasError) { return ( {i18n('icu:NavTabs__ItemIconLabel--HasError')} ! ); } if (hasPendingUpdate) { return
; } if (unreadStats != null) { if (unreadStats.unreadCount > 0) { return ( {i18n('icu:NavTabs__ItemIconLabel--UnreadCount', { count: unreadStats.unreadCount, })} {unreadStats.unreadCount} ); } if (unreadStats.markedUnread) { return ( {i18n('icu:NavTabs__ItemIconLabel--MarkedUnread')} ); } } return null; } type NavTabProps = Readonly<{ i18n: LocalizerType; iconClassName: string; id: NavTab; hasError?: boolean; label: string; unreadStats: UnreadStats | null; }>; function NavTabsItem({ i18n, iconClassName, id, label, unreadStats, hasError, }: NavTabProps) { const isRTL = i18n.getLocaleDirection() === 'rtl'; return ( {label} ); } export type NavTabPanelProps = Readonly<{ otherTabsUnreadStats: UnreadStats; collapsed: boolean; hasFailedStorySends: boolean; hasPendingUpdate: boolean; onToggleCollapse(collapsed: boolean): void; }>; export type NavTabsToggleProps = Readonly<{ otherTabsUnreadStats: UnreadStats | null; i18n: LocalizerType; hasFailedStorySends: boolean; hasPendingUpdate: boolean; navTabsCollapsed: boolean; onToggleNavTabsCollapse(navTabsCollapsed: boolean): void; }>; export function NavTabsToggle({ i18n, hasFailedStorySends, hasPendingUpdate, navTabsCollapsed, otherTabsUnreadStats, onToggleNavTabsCollapse, }: NavTabsToggleProps): JSX.Element { function handleToggle() { onToggleNavTabsCollapse(!navTabsCollapsed); } const label = navTabsCollapsed ? i18n('icu:NavTabsToggle__showTabs') : i18n('icu:NavTabsToggle__hideTabs'); const isRTL = i18n.getLocaleDirection() === 'rtl'; return ( ); } export type NavTabsProps = Readonly<{ badge: BadgeType | undefined; hasFailedStorySends: boolean; hasPendingUpdate: boolean; i18n: LocalizerType; me: ConversationType; navTabsCollapsed: boolean; onShowSettings: () => void; onStartUpdate: () => unknown; onNavTabSelected(tab: NavTab): void; onToggleNavTabsCollapse(collapsed: boolean): void; onToggleProfileEditor: () => void; renderCallsTab(props: NavTabPanelProps): JSX.Element; renderChatsTab(props: NavTabPanelProps): JSX.Element; renderStoriesTab(props: NavTabPanelProps): JSX.Element; selectedNavTab: NavTab; storiesEnabled: boolean; theme: ThemeType; unreadCallsCount: number; unreadConversationsStats: UnreadStats; unreadStoriesCount: number; }>; export function NavTabs({ badge, hasFailedStorySends, hasPendingUpdate, i18n, me, navTabsCollapsed, onShowSettings, onStartUpdate, onNavTabSelected, onToggleNavTabsCollapse, onToggleProfileEditor, renderCallsTab, renderChatsTab, renderStoriesTab, selectedNavTab, storiesEnabled, theme, unreadCallsCount, unreadConversationsStats, unreadStoriesCount, }: NavTabsProps): JSX.Element { function handleSelectionChange(key: Key) { onNavTabSelected(key as NavTab); } const isRTL = i18n.getLocaleDirection() === 'rtl'; return ( {renderChatsTab} {renderCallsTab} {renderStoriesTab} ); }