/* eslint-disable jsx-a11y/interactive-supports-focus */ import { useInfiniteQuery } from '@tanstack/react-query'; import clsx from 'clsx'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { Link, NavLink } from 'react-router-dom'; import { fetchOwnAccounts, logOut, switchAccount } from 'pl-fe/actions/auth'; import { useAccount } from 'pl-fe/api/hooks/accounts/use-account'; import Account from 'pl-fe/components/account'; import Divider from 'pl-fe/components/ui/divider'; import Icon from 'pl-fe/components/ui/icon'; import Stack from 'pl-fe/components/ui/stack'; import Text from 'pl-fe/components/ui/text'; import ProfileStats from 'pl-fe/features/ui/components/profile-stats'; import { useAppDispatch } from 'pl-fe/hooks/use-app-dispatch'; import { useAppSelector } from 'pl-fe/hooks/use-app-selector'; import { useFeatures } from 'pl-fe/hooks/use-features'; import { useInstance } from 'pl-fe/hooks/use-instance'; import { useRegistrationStatus } from 'pl-fe/hooks/use-registration-status'; import { useFollowRequestsCount } from 'pl-fe/queries/accounts/use-follow-requests'; import { scheduledStatusesCountQueryOptions } from 'pl-fe/queries/statuses/scheduled-statuses'; import { useDraftStatusesCountQuery } from 'pl-fe/queries/statuses/use-draft-statuses'; import { useInteractionRequestsCount } from 'pl-fe/queries/statuses/use-interaction-requests'; import { makeGetOtherAccounts } from 'pl-fe/selectors'; import { useSettingsStore } from 'pl-fe/stores/settings'; import { useUiStore } from 'pl-fe/stores/ui'; import sourceCode from 'pl-fe/utils/code'; import type { Account as AccountEntity } from 'pl-fe/normalizers/account'; const messages = defineMessages({ profile: { id: 'account.profile', defaultMessage: 'Profile' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, followedTags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' }, logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }, profileDirectory: { id: 'navigation_bar.profile_directory', defaultMessage: 'Profile directory' }, bookmarks: { id: 'column.bookmarks', defaultMessage: 'Bookmarks' }, lists: { id: 'column.lists', defaultMessage: 'Lists' }, circles: { id: 'column.circles', defaultMessage: 'Circles' }, groups: { id: 'column.groups', defaultMessage: 'Groups' }, events: { id: 'column.events', defaultMessage: 'Events' }, dashboard: { id: 'navigation.dashboard', defaultMessage: 'Dashboard' }, scheduledStatuses: { id: 'column.scheduled_statuses', defaultMessage: 'Scheduled posts' }, drafts: { id: 'navigation.drafts', defaultMessage: 'Drafts' }, addAccount: { id: 'profile_dropdown.add_account', defaultMessage: 'Add an existing account' }, followRequests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, interactionRequests: { id: 'navigation.interaction_requests', defaultMessage: 'Interaction requests' }, close: { id: 'lightbox.close', defaultMessage: 'Close' }, login: { id: 'account.login', defaultMessage: 'Log in' }, register: { id: 'account.register', defaultMessage: 'Sign up' }, sourceCode: { id: 'navigation.source_code', defaultMessage: 'Source code' }, conversations: { id: 'navigation.direct_messages', defaultMessage: 'Direct messages' }, }); interface IDropdownNavigationLink { href?: string; to?: string; icon: string; text: string | JSX.Element; onClick: React.EventHandler; } const DropdownNavigationLink: React.FC = React.memo(({ href, to, icon, text, onClick }) => { const body = ( <>
{text} ); if (to) { return ( {body} ); } return ( {body} ); }); const DropdownNavigation: React.FC = React.memo((): JSX.Element | null => { const intl = useIntl(); const dispatch = useAppDispatch(); const { isSidebarOpen, closeSidebar } = useUiStore(); const me = useAppSelector((state) => state.me); const authenticatedScheduledStatusesCountQueryOptions = useMemo(() => ({ ...scheduledStatusesCountQueryOptions, enabled: !!me, }), [me]); const getOtherAccounts = useCallback(makeGetOtherAccounts(), []); const features = useFeatures(); const { account } = useAccount(me || undefined); const otherAccounts = useAppSelector((state) => getOtherAccounts(state)); const { settings } = useSettingsStore(); const followRequestsCount = useFollowRequestsCount().data || 0; const interactionRequestsCount = useInteractionRequestsCount().data || 0; const scheduledStatusCount = useInfiniteQuery(authenticatedScheduledStatusesCountQueryOptions).data || 0; const { data: draftCount = 0 } = useDraftStatusesCountQuery(); // const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count()); const [sidebarVisible, setSidebarVisible] = useState(isSidebarOpen); const touchStart = useRef(0); const touchEnd = useRef(null); const { isOpen } = useRegistrationStatus(); const instance = useInstance(); const restrictUnauth = instance.pleroma.metadata.restrict_unauthenticated; const containerRef = React.useRef(null); const [switcher, setSwitcher] = React.useState(false); const handleClose = () => { setSwitcher(false); closeSidebar(); }; const handleSwitchAccount = (account: AccountEntity): React.MouseEventHandler => (e) => { e.preventDefault(); e.stopPropagation(); dispatch(switchAccount(account.id)); }; const onClickLogOut: React.MouseEventHandler = (e) => { e.preventDefault(); e.stopPropagation(); dispatch(logOut()); }; const handleSwitcherClick: React.MouseEventHandler = (e) => { e.preventDefault(); e.stopPropagation(); setSwitcher((prevState) => (!prevState)); }; const renderAccount = (account: AccountEntity) => (
); const handleKeyDown: React.KeyboardEventHandler = (e) => { if (e.key === 'Escape') handleClose(); }; const handleTouchStart: React.TouchEventHandler = (e) => touchStart.current = e.targetTouches[0].clientX; const handleTouchMove: React.TouchEventHandler = (e) => touchEnd.current = e.targetTouches[0].clientX; const handleTouchEnd: React.TouchEventHandler = (e) => { if (touchEnd.current !== null && touchStart.current - touchEnd.current > 100) { handleClose(); } touchEnd.current = null; }; useEffect(() => { dispatch(fetchOwnAccounts()); }, []); useEffect(() => { if (isSidebarOpen) containerRef.current?.querySelector('a')?.focus(); setTimeout(() => setSidebarVisible(isSidebarOpen), isSidebarOpen ? 0 : 150); }, [isSidebarOpen]); return (
{account ? (
{!settings.demetricator && ( )} {(account.locked || followRequestsCount > 0) && ( )} {(interactionRequestsCount > 0) && ( )} {features.conversations && ( )} {features.bookmarks && ( )} {features.groups && ( )} {features.lists && ( )} {features.circles && ( )} {features.events && ( )} {features.profileDirectory && ( )} {scheduledStatusCount > 0 && ( )} {draftCount > 0 && ( )} {features.publicTimeline && <> : } onClick={closeSidebar} /> {features.bubbleTimeline && ( } onClick={closeSidebar} /> )} {features.federating && ( } onClick={closeSidebar} /> )} {features.wrenchedTimeline && ( } onClick={closeSidebar} /> )} } {features.followedHashtagsList && ( )} {(account.is_admin || account.is_moderator) && ( )}
{switcher && (
{otherAccounts.map(account => renderAccount(account))} {intl.formatMessage(messages.addAccount)}
)}
) : (
{features.publicTimeline && !restrictUnauth.timelines.local && <> : } onClick={closeSidebar} /> {features.bubbleTimeline && !restrictUnauth.timelines.bubble && ( } onClick={closeSidebar} /> )} {features.federating && !restrictUnauth.timelines.federated && ( } onClick={closeSidebar} /> )} {features.wrenchedTimeline && !restrictUnauth.timelines.wrenched && ( } onClick={closeSidebar} /> )} } {isOpen && ( )}
)}
); }); export { DropdownNavigation as default };