// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Key, ReactNode } from 'react';
import React, { useState } 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, ProfileEditorPage, SettingsPage } from '../types/Nav';
import type { Location } from '../types/Nav';
import { Tooltip, TooltipPlacement } from './Tooltip';
import { Theme } from '../util/theme';
import type { UnreadStats } from '../util/countUnreadStats';
import { ProfileMovedModal } from './ProfileMovedModal';
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;
onChangeLocation: (location: Location) => void;
onDismissProfileMovedModal: () => void;
onToggleNavTabsCollapse: (collapsed: boolean) => void;
profileMovedModalNeeded: boolean;
renderCallsTab: () => ReactNode;
renderChatsTab: () => ReactNode;
renderStoriesTab: () => ReactNode;
renderSettingsTab: () => ReactNode;
selectedNavTab: NavTab;
shouldShowProfileIcon: boolean;
storiesEnabled: boolean;
theme: ThemeType;
unreadCallsCount: number;
unreadConversationsStats: UnreadStats;
unreadStoriesCount: number;
}>;
export function NavTabs({
badge,
hasFailedStorySends,
hasPendingUpdate,
i18n,
me,
navTabsCollapsed,
onChangeLocation,
onDismissProfileMovedModal,
onToggleNavTabsCollapse,
profileMovedModalNeeded,
renderCallsTab,
renderChatsTab,
renderStoriesTab,
renderSettingsTab,
selectedNavTab,
shouldShowProfileIcon,
storiesEnabled,
theme,
unreadCallsCount,
unreadConversationsStats,
unreadStoriesCount,
}: NavTabsProps): JSX.Element {
const [showingProfileMovedModal, setShowingProfileMovedModal] =
useState(false);
function handleSelectionChange(key: Key) {
const tab = key as NavTab;
if (tab === NavTab.Settings) {
onChangeLocation({
tab: NavTab.Settings,
details: {
page: SettingsPage.Profile,
state: ProfileEditorPage.None,
},
});
} else {
onChangeLocation({ tab });
}
}
const isRTL = i18n.getLocaleDirection() === 'rtl';
return (
{showingProfileMovedModal ? (
{
setShowingProfileMovedModal(false);
onDismissProfileMovedModal();
}}
theme={theme}
/>
) : undefined}
{renderChatsTab}
{renderCallsTab}
{renderStoriesTab}
{renderSettingsTab}
);
}