diff --git a/src/components/addresses/picker/AddressPicker.less b/src/components/addresses/picker/AddressPicker.less
index 82352d0..b25e5d9 100644
--- a/src/components/addresses/picker/AddressPicker.less
+++ b/src/components/addresses/picker/AddressPicker.less
@@ -29,12 +29,13 @@
flex: 1;
}
- .address-picker-wallet-label {
+ .address-picker-wallet-label, .address-picker-contact-label {
white-space: normal;
word-break: break-word;
}
- .address-picker-wallet-label + .address-picker-wallet-address {
+ .address-picker-wallet-label + .address-picker-wallet-address,
+ .address-picker-contact-label + .address-picker-contact-address {
color: @text-color-secondary;
}
}
diff --git a/src/components/addresses/picker/AddressPicker.tsx b/src/components/addresses/picker/AddressPicker.tsx
index bd66f64..4b08d4f 100644
--- a/src/components/addresses/picker/AddressPicker.tsx
+++ b/src/components/addresses/picker/AddressPicker.tsx
@@ -11,6 +11,7 @@
import { useTranslation } from "react-i18next";
import { useWallets } from "@wallets";
+import { useContacts } from "@contacts";
import {
useAddressPrefix, useNameSuffix,
isValidAddress, getNameParts,
@@ -78,7 +79,9 @@
// (and soon the address book too), but to save on time and expense, the
// 'exact address' match is prepended to these options dynamically.
const { wallets, addressList } = useWallets();
- const options = useMemo(() => getOptions(t, wallets), [t, wallets]);
+ const { contacts, contactAddressList } = useContacts();
+ const options = useMemo(() => getOptions(t, wallets, contacts),
+ [t, wallets, contacts]);
// Check if the input text is an exact address. If it is, create an extra item
// to prepend to the list. Note that the 'exact address' item is NOT shown if
@@ -241,6 +244,7 @@
const address = option!.value?.toUpperCase();
const walletLabel = option!["data-wallet-label"]?.toUpperCase();
+ const contactLabel = option!["data-contact-label"]?.toUpperCase();
// If we have another address picker's value, hide that option from
// the list (it will always be a wallet)
@@ -258,8 +262,9 @@
const matchedAddress = address.indexOf(inp) !== -1;
const matchedLabel = walletLabel?.indexOf(inp) !== -1;
+ const matchedContactLabel = contactLabel?.indexOf(inp) !== -1;
- return matchedAddress || matchedLabel;
+ return matchedAddress || matchedLabel || matchedContactLabel;
}}
options={fullOptions}
diff --git a/src/components/addresses/picker/Item.tsx b/src/components/addresses/picker/Item.tsx
index f4b2e21..793deea 100644
--- a/src/components/addresses/picker/Item.tsx
+++ b/src/components/addresses/picker/Item.tsx
@@ -3,6 +3,7 @@
// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt
import { Wallet } from "@wallets";
+import { Contact } from "@contacts";
import { NameParts } from "@utils/currency";
import { KristValue } from "@comp/krist/KristValue";
@@ -13,10 +14,17 @@
address?: string;
name?: NameParts;
wallet?: Wallet;
+ contact?: Contact;
}
-function getPlainAddress({ address, name, wallet }: AddressItemProps): string {
+function getPlainAddress({
+ address,
+ name,
+ wallet,
+ contact
+}: AddressItemProps): string {
if (wallet) return wallet.address;
+ if (contact) return contact.address;
if (name?.recipient) return name.recipient;
else return address || "";
}
@@ -24,14 +32,21 @@
function PickerContent({
name,
wallet,
+ contact,
plainAddress
}: AddressItemProps & { plainAddress: string }): JSX.Element {
- if (wallet && wallet.label) {
+ if (wallet?.label) {
// Show the wallet label if possible
return <>
{wallet.label}
({wallet.address})
>;
+ } else if (contact?.label) {
+ // Show the contact label if possible
+ return <>
+ {contact.label}
+ ({contact.address})
+ >;
} else if (name?.recipient) {
// Show a formatted name if possible
const { metaname, nameWithSuffix } = name;
@@ -49,12 +64,12 @@
export function getAddressItem(props: AddressItemProps): OptionValue {
// The address to use as a value
const plainAddress = getPlainAddress(props);
- const { wallet } = props;
+ const { wallet, contact } = props;
return {
label: (
- {/* Address, wallet label, or name */}
+ {/* Address, wallet label, contact label, or name */}
@@ -66,8 +81,10 @@
// The wallet label is used for filtering the options
"data-wallet-label": wallet?.label,
+ "data-contact-label": contact?.label,
// The wallet itself is used for sorting the options
"data-wallet": wallet,
+ "data-contact": contact,
value: plainAddress
};
diff --git a/src/components/addresses/picker/options.ts b/src/components/addresses/picker/options.ts
index 0b9aff5..9c9c231 100644
--- a/src/components/addresses/picker/options.ts
+++ b/src/components/addresses/picker/options.ts
@@ -4,6 +4,7 @@
import { TFunction } from "react-i18next";
import { WalletMap, Wallet } from "@wallets";
+import { ContactMap, Contact } from "@contacts";
import { getCategoryHeader } from "./Header";
import { getAddressItem } from "./Item";
@@ -21,7 +22,9 @@
// For some reason, all these props get passed all the way to the DOM element!
// Make this a 'valid' DOM prop
"data-wallet-label"?: string;
+ "data-contact-label"?: string;
"data-wallet"?: Wallet;
+ "data-contact"?: Contact;
value: string;
}
@@ -39,6 +42,7 @@
interface WalletOptions {
categorised: Record
;
uncategorised: OptionValue[];
+ contacts: OptionValue[];
categoryCount: number;
}
@@ -46,18 +50,30 @@
// the bottom by using keyedNullSort. Addresses are sorted ascending, though
// because of the implicit reversing behaviour of keyedNullSort, they need to
// be swapped here (i.e. sort with `b`, `a`).
-const sortBalance = keyedNullSort("balance");
-const sortAddress = keyedNullSort("address", true);
+const sortBalance = keyedNullSort<{ balance?: number }>("balance");
+const sortLabel = keyedNullSort<{ label?: string }>("label", true);
+const sortAddress = keyedNullSort<{ address: string }>("address", true);
+
const sortFn = (a: Wallet, b: Wallet): number =>
sortBalance(a, b, "descend") || sortAddress(b, a);
const optionSortFn = (a: OptionValue, b: OptionValue): number =>
sortFn(a["data-wallet"]!, b["data-wallet"]!);
+const contactSortFn = (a: Contact, b: Contact): number =>
+ sortLabel(b, a) || sortAddress(b, a);
+const contactOptionSortFn = (a: OptionValue, b: OptionValue): number =>
+ contactSortFn(a["data-contact"]!, b["data-contact"]!);
+
/** Groups the wallets by category for autocompletion and generates their select
* options. */
-function getWalletOptions(wallets: WalletMap): WalletOptions {
+function getWalletOptions(
+ wallets: WalletMap,
+ contacts: ContactMap
+): WalletOptions {
const categorised: Record = {};
const uncategorised: OptionValue[] = [];
+ const contactValues: OptionValue[] = Object.values(contacts)
+ .map(contact => getAddressItem({ contact }));
// Go through all wallets and group them
for (const id in wallets) {
@@ -84,12 +100,17 @@
categorised[category].sort(optionSortFn);
categorised[category].reverse();
}
+
uncategorised.sort(optionSortFn);
uncategorised.reverse();
+ contactValues.sort(contactOptionSortFn);
+ contactValues.reverse();
+
return {
categorised,
uncategorised,
+ contacts: contactValues,
categoryCount: Object.keys(categorised).length
};
}
@@ -99,10 +120,14 @@
// -----------------------------------------------------------------------------
/** Gets the base options to show for autocompletion, including the wallets,
* grouped by category if possible. Will include the address book soon too. */
-export function getOptions(t: TFunction, wallets: WalletMap): Option[] {
+export function getOptions(
+ t: TFunction,
+ wallets: WalletMap,
+ contactMap: ContactMap,
+): Option[] {
// Wallet options
- const { categorised, uncategorised, categoryCount }
- = getWalletOptions(wallets);
+ const { categorised, uncategorised, categoryCount, contacts }
+ = getWalletOptions(wallets, contactMap);
// Sort the wallet categories in a human-friendly manner
const sortedCategories = Object.keys(categorised);
@@ -130,6 +155,10 @@
options: uncategorised
},
- // TODO: Address book
+ // Address book
+ {
+ ...getCategoryHeader(t("addressPicker.categoryAddressBook")),
+ options: contacts
+ },
];
}
diff --git a/src/pages/addresses/AddressButtonRow.tsx b/src/pages/addresses/AddressButtonRow.tsx
index 1fa174c..638914e 100644
--- a/src/pages/addresses/AddressButtonRow.tsx
+++ b/src/pages/addresses/AddressButtonRow.tsx
@@ -54,7 +54,6 @@
)}
{/* Add contact/edit wallet button */}
- {/* TODO: Change this to edit if they're already a contact */}
{myWallet
? (