// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. import React, {ReactNode, useRef, createRef, useState, useEffect, MutableRefObject} from 'react' import './boardSwitcherDialog.scss' import {useIntl} from 'react-intl' import {generatePath, useHistory, useRouteMatch} from 'react-router-dom' import octoClient from '../../octoClient' import SearchDialog from '../searchDialog/searchDialog' import Globe from '../../widgets/icons/globe' import LockOutline from '../../widgets/icons/lockOutline' import {useAppSelector} from '../../store/hooks' import {getAllTeams, getCurrentTeam, Team} from '../../store/teams' import {getMe} from '../../store/users' import {Utils} from '../../utils' import {BoardTypeOpen, BoardTypePrivate} from '../../blocks/board' import {Constants} from '../../constants' type Props = { onClose: () => void } const BoardSwitcherDialog = (props: Props): JSX.Element => { const [selected, setSelected] = useState(-1) // eslint-disable-next-line @typescript-eslint/no-explicit-any const [refs, setRefs] = useState>(useRef([])) // eslint-disable-next-line @typescript-eslint/no-explicit-any const [IDs, setIDs] = useState({}) const intl = useIntl() const team = useAppSelector(getCurrentTeam) const me = useAppSelector(getMe) const title = intl.formatMessage({id: 'FindBoardsDialog.Title', defaultMessage: 'Find Boards'}) const subTitle = intl.formatMessage( { id: 'FindBoardsDialog.SubTitle', defaultMessage: 'Type to find a board. Use UP/DOWN to browse. ENTER to select, ESC to dismiss', }, { b: (...chunks) => {chunks}, }, ) const match = useRouteMatch<{boardId: string, viewId: string, cardId?: string}>() const history = useHistory() const selectBoard = async (teamId: string, boardId: string): Promise => { if (!me) { return } const newPath = generatePath(Utils.getBoardPagePath(match.path), {...match.params, teamId, boardId, viewId: undefined}) history.push(newPath) props.onClose() } const teamsById: Record = {} useAppSelector(getAllTeams).forEach((t) => { teamsById[t.id] = t }) const searchHandler = async (query: string): Promise => { if (query.trim().length === 0 || !team) { return [] } const items = await octoClient.searchAll(query) const untitledBoardTitle = intl.formatMessage({id: 'ViewTitle.untitled-board', defaultMessage: 'Untitled board'}) refs.current = items.map((_, i) => refs.current[i] ?? createRef()) setRefs(refs) return items.map((item, i) => { const resultTitle = item.title || untitledBoardTitle const teamTitle = teamsById[item.teamId].title // eslint-disable-next-line @typescript-eslint/no-explicit-any setIDs((prevIDs: any) => ({ ...prevIDs, [i]: [item.teamId, item.id], })) return (
selectBoard(item.teamId, item.id)} ref={refs.current[i]} > {item.type === BoardTypeOpen && } {item.type === BoardTypePrivate && } {resultTitle} {teamTitle}
) }) } const handleEnterKeyPress = (e: KeyboardEvent) => { if (Utils.isKeyPressed(e, Constants.keyCodes.ENTER) && selected > -1) { e.preventDefault() const [teamId, id] = IDs[selected] selectBoard(teamId, id) } } useEffect(() => { if (selected >= 0) { refs.current[selected].current.parentElement.focus() } document.addEventListener('keydown', handleEnterKeyPress) // cleanup function return () => { document.removeEventListener('keydown', handleEnterKeyPress) } }, [selected, refs, IDs]) return ( setSelected(n)} /> ) } export default BoardSwitcherDialog