// Copyright 2023 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { Key, ReactNode } from 'react'; import React from 'react'; import { Tabs, TabList, Tab, 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'; 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<{ hasError?: boolean; i18n: LocalizerType; iconClassName: string; id: NavTab; label: string; navTabClassName: string; unreadStats: UnreadStats | null; hasPendingUpdate?: boolean; }>; function NavTabsItem({ hasError, i18n, iconClassName, id, label, navTabClassName, unreadStats, hasPendingUpdate, }: 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; onNavTabSelected: (tab: NavTab) => void; onToggleNavTabsCollapse: (collapsed: boolean) => void; onToggleProfileEditor: () => void; renderCallsTab: () => ReactNode; renderChatsTab: () => ReactNode; renderStoriesTab: () => ReactNode; renderSettingsTab: () => ReactNode; selectedNavTab: NavTab; storiesEnabled: boolean; theme: ThemeType; unreadCallsCount: number; unreadConversationsStats: UnreadStats; unreadStoriesCount: number; }>; export function NavTabs({ badge, hasFailedStorySends, hasPendingUpdate, i18n, me, navTabsCollapsed, onNavTabSelected, onToggleNavTabsCollapse, onToggleProfileEditor, renderCallsTab, renderChatsTab, renderStoriesTab, renderSettingsTab, 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} {renderSettingsTab} ); }