{"size": 3841, "ext": "js", "max_stars_repo_path": "src/sidebar/components/UserMenu.js", "max_stars_repo_name": "elias-sundqvist/hypothesis-client-annotator-fork", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "src/sidebar/components/UserMenu.js", "max_issues_repo_name": "elias-sundqvist/hypothesis-client-annotator-fork", "max_issues_repo_issues_event_min_datetime": null, "max_issues_repo_issues_event_max_datetime": null, "max_forks_repo_path": "src/sidebar/components/UserMenu.js", "max_forks_repo_name": "elias-sundqvist/hypothesis-client-annotator-fork", "max_forks_repo_forks_event_min_datetime": null, "max_forks_repo_forks_event_max_datetime": null}
{"max_stars_count": null, "max_issues_count": null, "max_forks_count": null, "avg_line_length": 29.7751937984, "max_line_length": 90, "alphanum_fraction": 0.6381150742}
import { Icon } from '@hypothesis/frontend-shared';
import { useState } from 'preact/hooks';

import { serviceConfig } from '../config/service-config';
import { isThirdPartyUser } from '../helpers/account-id';
import { withServices } from '../service-context';
import { useSidebarStore } from '../store';

import Menu from './Menu';
import MenuItem from './MenuItem';
import MenuSection from './MenuSection';

/**
 * @typedef {import('../../types/config').SidebarSettings} SidebarSettings
 * /

/**
 * @typedef AuthStateLoggedIn
 * @prop {'logged-in'} status
 * @prop {string} displayName
 * @prop {string} userid
 * @prop {string} username
 * @typedef {{status: 'logged-out'|'unknown'} | AuthStateLoggedIn}  AuthState
 */

/**
 * @typedef UserMenuProps
 * @prop {AuthStateLoggedIn} auth - object representing authenticated user and auth status
 * @prop {() => void} onLogout - onClick callback for the "log out" button
 * @prop {import('../services/frame-sync').FrameSyncService} frameSync
 * @prop {SidebarSettings} settings
 */

/**
 * A menu with user and account links.
 *
 * This menu will contain different items depending on service configuration,
 * context and whether the user is first- or third-party.
 *
 * @param {UserMenuProps} props
 */
function UserMenu({ auth, frameSync, onLogout, settings }) {
  const store = useSidebarStore();
  const defaultAuthority = store.defaultAuthority();

  const isThirdParty = isThirdPartyUser(auth.userid, defaultAuthority);
  const service = serviceConfig(settings);
  const [isOpen, setOpen] = useState(false);

  /** @param {keyof import('../../types/config').Service} feature */
  const serviceSupports = feature => service && !!service[feature];

  const isSelectableProfile =
    !isThirdParty || serviceSupports('onProfileRequestProvided');
  const isLogoutEnabled =
    !isThirdParty || serviceSupports('onLogoutRequestProvided');

  const onSelectNotebook = () => {
    frameSync.notifyHost('openNotebook', store.focusedGroupId());
  };

  // Temporary access to the Notebook without feature flag:
  // type the key 'n' when user menu is focused/open

  /** @param {KeyboardEvent} event */
  const onKeyDown = event => {
    if (event.key === 'n') {
      onSelectNotebook();
      setOpen(false);
    }
  };

  const onProfileSelected = () =>
    isThirdParty && frameSync.notifyHost('profileRequested');

  // Generate dynamic props for the profile <MenuItem> component
  const profileItemProps = (() => {
    const props = {};
    if (isSelectableProfile) {
      if (!isThirdParty) {
        props.href = store.getLink('user', { user: auth.username });
      }
      props.onClick = onProfileSelected;
    }
    return props;
  })();

  const menuLabel = (
    <span className="p-1">
      <Icon name="profile" />
    </span>
  );
  return (
    // Allow keyboard shortcut 'n' to open Notebook
    /* eslint-disable-next-line jsx-a11y/no-static-element-interactions */
    <div data-testid="user-menu" onKeyDown={onKeyDown}>
      <Menu
        label={menuLabel}
        title={auth.displayName}
        align="right"
        open={isOpen}
        onOpenChanged={setOpen}
      >
        <MenuSection>
          <MenuItem
            label={auth.displayName}
            isDisabled={!isSelectableProfile}
            {...profileItemProps}
          />
          {!isThirdParty && (
            <MenuItem
              label="Account settings"
              href={store.getLink('account.settings')}
            />
          )}
          <MenuItem label="Open notebook" onClick={() => onSelectNotebook()} />
        </MenuSection>
        {isLogoutEnabled && (
          <MenuSection>
            <MenuItem label="Log out" onClick={onLogout} />
          </MenuSection>
        )}
      </Menu>
    </div>
  );
}

export default withServices(UserMenu, ['frameSync', 'settings']);
