diff --git a/src/Platform/Hosted/Components/SearchableDropdown.tsx b/src/Platform/Hosted/Components/SearchableDropdown.tsx new file mode 100644 index 000000000..7123d2616 --- /dev/null +++ b/src/Platform/Hosted/Components/SearchableDropdown.tsx @@ -0,0 +1,87 @@ +import { Callout, DefaultButton, DirectionalHint, Stack, TextField } from "office-ui-fabric-react"; +import React from "react"; + +export interface DropdownItem { + key: string; + text: string; +} + +export interface SearchableDropdownProps { + items: DropdownItem[]; + onItemSelected: (selectedItem: DropdownItem) => void; + defaultSelectedItem?: DropdownItem; + placeholder?: string; + title?: string; +} + +export interface SearchableDropdownState { + isDropdownExpanded: boolean; + selectedItem: DropdownItem; + filteredItems: DropdownItem[]; +} + +export class SearchableDropdown extends React.Component { + constructor(props: SearchableDropdownProps) { + super(props); + + this.state = { + isDropdownExpanded: false, + selectedItem: props.defaultSelectedItem, + filteredItems: props.items, + }; + } + + public render(): JSX.Element { + return this.state.isDropdownExpanded ? ( + + this.onSearchInputChange(newInput)} + placeholder={this.props.placeholder} + autoFocus + /> + this.setState({ isDropdownExpanded: false })} + gapSpace={0} + > + + {this.state.filteredItems?.map((item) => ( + this.onItemSelected(item)} + /> + ))} + + + + ) : ( + this.setState({ isDropdownExpanded: true, filteredItems: this.props.items })} + value={this.state.selectedItem?.text || ""} + placeholder={this.props.placeholder} + readOnly + /> + ); + } + + private onSearchInputChange(newInput: string): void { + const filteredItems = this.props.items.filter((item: DropdownItem) => + item.text.toLocaleLowerCase().includes(newInput.toLocaleLowerCase()) + ); + this.setState({ filteredItems }); + } + + private onItemSelected(item: DropdownItem): void { + this.setState({ selectedItem: item, isDropdownExpanded: false }); + this.props.onItemSelected(item); + } +} diff --git a/src/Platform/Hosted/Components/SwitchAccount.tsx b/src/Platform/Hosted/Components/SwitchAccount.tsx index 204f64b78..e85680ed7 100644 --- a/src/Platform/Hosted/Components/SwitchAccount.tsx +++ b/src/Platform/Hosted/Components/SwitchAccount.tsx @@ -1,7 +1,6 @@ -import { Dropdown } from "office-ui-fabric-react/lib/Dropdown"; -import * as React from "react"; -import { FunctionComponent } from "react"; +import React from "react"; import { DatabaseAccount } from "../../../Contracts/DataModels"; +import { DropdownItem, SearchableDropdown } from "./SearchableDropdown"; interface Props { accounts: DatabaseAccount[]; @@ -10,30 +9,32 @@ interface Props { dismissMenu: () => void; } -export const SwitchAccount: FunctionComponent = ({ +export const SwitchAccount: React.FunctionComponent = ({ accounts, setSelectedAccountName, selectedAccount, - dismissMenu, + dismissMenu }: Props) => { + const accountItems = accounts?.map((account) => ({ + key: account.name, + text: account.name, + })); + + const defaultAccount = selectedAccount && { + key: selectedAccount.name, + text: selectedAccount.name, + }; + return ( - ({ - key: account.name, - text: account.name, - data: account, - }))} - onChange={(_, option) => { - setSelectedAccountName(String(option.key)); + { + setSelectedAccountName(accountItem.key); dismissMenu(); }} - defaultSelectedKey={selectedAccount?.name} - placeholder={accounts && accounts.length === 0 ? "No Accounts Found" : "Select an Account"} - styles={{ - callout: "accountSwitchAccountDropdownMenu", - }} /> ); }; diff --git a/src/Platform/Hosted/Components/SwitchSubscription.tsx b/src/Platform/Hosted/Components/SwitchSubscription.tsx index f6b404bda..55f8d4304 100644 --- a/src/Platform/Hosted/Components/SwitchSubscription.tsx +++ b/src/Platform/Hosted/Components/SwitchSubscription.tsx @@ -1,7 +1,6 @@ -import { Dropdown } from "office-ui-fabric-react/lib/Dropdown"; -import * as React from "react"; -import { FunctionComponent } from "react"; +import React from "react"; import { Subscription } from "../../../Contracts/DataModels"; +import { DropdownItem, SearchableDropdown } from "./SearchableDropdown"; interface Props { subscriptions: Subscription[]; @@ -9,30 +8,28 @@ interface Props { setSelectedSubscriptionId: (id: string) => void; } -export const SwitchSubscription: FunctionComponent = ({ +export const SwitchSubscription: React.FunctionComponent = ({ subscriptions, setSelectedSubscriptionId, selectedSubscription, }: Props) => { + const subscriptionItems = subscriptions?.map((sub) => ({ + key: sub.subscriptionId, + text: sub.displayName, + })); + + const defaultSubscription = selectedSubscription && { + key: selectedSubscription.subscriptionId, + text: selectedSubscription.displayName, + }; + return ( - { - return { - key: sub.subscriptionId, - text: sub.displayName, - data: sub, - }; - })} - onChange={(_, option) => { - setSelectedSubscriptionId(String(option.key)); - }} - defaultSelectedKey={selectedSubscription?.subscriptionId} - placeholder={subscriptions && subscriptions.length === 0 ? "No Subscriptions Found" : "Select a Subscription"} - styles={{ - callout: "accountSwitchSubscriptionDropdownMenu", - }} + setSelectedSubscriptionId(subscriptionItem.key)} /> ); };