Skip to content

Commit

Permalink
Adjust autocomplete suggestions to design
Browse files Browse the repository at this point in the history
  • Loading branch information
serjonya-trili committed Oct 7, 2023
1 parent 91a8fd4 commit 0c67a3d
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { FormProvider, useForm } from "react-hook-form";
import { mockContact, mockImplicitAddress } from "../mocks/factories";
import { fireEvent, render, renderHook, screen, within } from "../mocks/testUtils";
import { Contact } from "../types/Contact";
import { mockContact, mockImplicitAddress } from "../../mocks/factories";
import { fireEvent, render, renderHook, screen, within } from "../../mocks/testUtils";
import { Contact } from "../../types/Contact";
import { AddressAutocomplete, getSuggestions } from "./AddressAutocomplete";
import store from "../../utils/redux/store";
import { contactsActions } from "../../utils/redux/slices/contactsSlice";

type FormFields = { destination: string };

Expand Down Expand Up @@ -95,6 +97,8 @@ describe("<AddressAutocomplete />", () => {
});

it("displays suggestions if user input has suggestions", async () => {
store.dispatch(contactsActions.upsert(mockContact(0)));
store.dispatch(contactsActions.upsert(mockContact(1)));
fixture({});
const rawInput = screen.getByLabelText("destination");

Expand All @@ -108,10 +112,12 @@ describe("<AddressAutocomplete />", () => {
expect(suggestions).toHaveLength(3);
expect(within(suggestionContainer).getByText(mockContact(0).name)).toBeInTheDocument();
expect(within(suggestionContainer).getByText(mockContact(1).name)).toBeInTheDocument();
expect(within(suggestionContainer).getByText(mockContact(2).name)).toBeInTheDocument();
// this one is unknown and its full address will be shows
expect(within(suggestionContainer).getByText(mockContact(2).pkh)).toBeInTheDocument();
});

test("choosing a suggestions submits the pkh, inputs the contact name and hides suggestions", () => {
store.dispatch(contactsActions.upsert(mockContact(1)));
fixture({});
const rawInput = screen.getByLabelText("destination");
const realInput = screen.getByTestId("real-address-input-destination");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { Box, FormLabel, Input, ListItem, StyleProps, UnorderedList } from "@chakra-ui/react";
import { Box, FormLabel, Input, StyleProps } from "@chakra-ui/react";
import { get } from "lodash";
import { useId, useState } from "react";
import { FieldValues, Path, RegisterOptions, useFormContext } from "react-hook-form";
import colors from "../style/colors";
import { Account } from "../types/Account";
import { isAddressValid } from "../types/Address";
import { Contact } from "../types/Contact";
import { Account } from "../../types/Account";
import { isAddressValid } from "../../types/Address";
import { Contact } from "../../types/Contact";
import {
useAllAccounts,
useGetOwnedSignersForAccount,
useImplicitAccounts,
} from "../utils/hooks/accountHooks";
import { useBakerList } from "../utils/hooks/assetsHooks";
import { useContacts } from "../utils/hooks/contactsHooks";
import { AccountSmallTileDisplay } from "./AccountSelector/AccountSmallTileDisplay";
} from "../../utils/hooks/accountHooks";
import { useBakerList } from "../../utils/hooks/assetsHooks";
import { useContacts } from "../../utils/hooks/contactsHooks";
import { Suggestions } from "./Suggestions";

// <T extends FieldValues> is needed to be compatible with the useForm's type parameter (FormData)
// <U extends Path<T>> makes sure that we can pass in only valid inputName that exists in FormData
Expand Down Expand Up @@ -49,60 +48,6 @@ export const getSuggestions = (inputValue: string, contacts: Contact[]): Contact
return result;
};

// TODO: Display different types of suggestions differently
// e.g. implicit vs contract vs contact vs baker
const Suggestions = ({
contacts,
onChange,
}: {
contacts: Contact[];
onChange: (name: string) => void;
}) => {
return contacts.length === 0 ? null : (
<UnorderedList
data-testid="suggestions-list"
overflowY="auto"
mt="8px"
ml={0}
width="100%"
borderRadius="8px"
listStyleType="none"
position="absolute"
border="1px solid"
borderColor={colors.gray[500]}
bg={colors.gray[700]}
zIndex={2}
maxHeight={300}
>
{contacts.map((contact, i) => (
<Box key={contact.pkh}>
<ListItem
onMouseDown={() => {
// onMouseDown is the only way for this to fire before the onBlur callback of the Input
// https://stackoverflow.com/a/28963938/6797267
onChange(contact.name);
}}
padding="5px 15px 0 5px"
mb={i === contacts.length - 1 ? "5px" : 0}
>
<AccountSmallTileDisplay
pkh={contact.pkh}
label={contact.name}
_hover={{
background: colors.gray[500],
}}
borderRadius="4px"
padding="5px"
height="40px"
balance={undefined} // TODO: add balance where possible
/>
</ListItem>
</Box>
))}
</UnorderedList>
);
};

// TODO: add chevron and cross buttons
export const AddressAutocomplete = <T extends FieldValues, U extends Path<T>>({
contacts,
Expand Down
62 changes: 62 additions & 0 deletions src/components/AddressAutocomplete/Suggestions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { Box, ListItem, UnorderedList } from "@chakra-ui/react";
import { Contact } from "../../types/Contact";
import colors from "../../style/colors";
import { parsePkh } from "../../types/Address";
import AddressTile from "../AddressTile/AddressTile";

export const Suggestions = ({
contacts,
onChange,
}: {
contacts: Contact[];
onChange: (name: string) => void;
}) => {
if (contacts.length === 0) {
return null;
}

return (
<UnorderedList
data-testid="suggestions-list"
overflowY="auto"
mt="8px"
ml={0}
width="100%"
borderRadius="8px"
listStyleType="none"
position="absolute"
border="1px solid"
borderColor={colors.gray[500]}
bg={colors.gray[700]}
zIndex={2}
maxHeight={300}
>
{contacts.map((contact, i) => (
<Box key={contact.pkh}>
<ListItem
onMouseDown={() => {
// onMouseDown is the only way for this to fire before the onBlur callback of the Input
// https://stackoverflow.com/a/28963938/6797267
onChange(contact.name);
}}
padding="5px 15px 0 5px"
mb={i === contacts.length - 1 ? "5px" : 0}
>
<AddressTile
cursor="pointer"
address={parsePkh(contact.pkh)}
_hover={{
background: colors.gray[500],
}}
background={colors.gray[700]}
width="370px"
borderRadius="4px"
padding="5px"
height="40px"
/>
</ListItem>
</Box>
))}
</UnorderedList>
);
};
1 change: 1 addition & 0 deletions src/components/AddressAutocomplete/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./AddressAutocomplete";
8 changes: 4 additions & 4 deletions src/components/AddressTile/AddressTile.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Flex, Text, Heading, FlexProps } from "@chakra-ui/react";
import { Flex, Text, Heading, FlexProps, Box } from "@chakra-ui/react";
import { Address } from "../../types/Address";
import useAddressKind from "./useAddressKind";
import AddressTileIcon from "./AddressTileIcon";
Expand Down Expand Up @@ -30,17 +30,17 @@ const AddressTile: React.FC<{ address: Address } & FlexProps> = ({ address, ...f
</Text>
) : (
<>
<Heading size="sm" ml="12px">
<Heading size="sm" ml="12px" width="102px">
{truncate(addressKind.label, 15)}
</Heading>
<Text color={colors.gray[300]} size="sm" ml="10px">
<Text color={colors.gray[300]} size="xs" ml="10px" width="88px">
{formatPkh(addressKind.pkh)}
</Text>
</>
)}
</Flex>

{balance && <PrettyNumber number={prettyTezAmount(balance)} />}
<Box textAlign="right">{balance && <PrettyNumber number={prettyTezAmount(balance)} />}</Box>
</Flex>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/AddressTile/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ export type BakerAddress = AddressKindBase & { type: "baker"; label: string };
export type ContactAddress = AddressKindBase & { type: "contact"; label: string };
export type UnknownAddress = AddressKindBase & { type: "unknown"; label: null };

export type OwnedAddreess = MnemonicAddress | SocialAddress | LedgerAddress | OwnedMultisigAddress;
export type OwnedAddress = MnemonicAddress | SocialAddress | LedgerAddress | OwnedMultisigAddress;

export type AddressKind = OwnedAddreess | BakerAddress | ContactAddress | UnknownAddress;
export type AddressKind = OwnedAddress | BakerAddress | ContactAddress | UnknownAddress;
4 changes: 2 additions & 2 deletions src/components/AddressTile/useAddressKind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Address } from "../../types/Address";
import { useGetOwnedAccountSafe } from "../../utils/hooks/accountHooks";
import { useGetBaker } from "../../utils/hooks/assetsHooks";
import { useGetContactName } from "../../utils/hooks/contactsHooks";
import { AddressKind, BakerAddress, ContactAddress, OwnedAddreess } from "./types";
import { AddressKind, BakerAddress, ContactAddress, OwnedAddress } from "./types";

const useAddressKind = (address: Address): AddressKind => {
const ownedAccount = useOwnedAccountAddressKind(address);
Expand All @@ -18,7 +18,7 @@ const useAddressKind = (address: Address): AddressKind => {

export default useAddressKind;

export const useOwnedAccountAddressKind = ({ pkh }: Address): OwnedAddreess | null => {
export const useOwnedAccountAddressKind = ({ pkh }: Address): OwnedAddress | null => {
const getOwnedAccount = useGetOwnedAccountSafe();
const account = getOwnedAccount(pkh);
if (!account) {
Expand Down

0 comments on commit 0c67a3d

Please sign in to comment.