Contacts List
One central feature of BasicPay is a list of contacts containing a user's name and associated Stellar addresses.
User experience
There are a few ways for a user to interact with the contact list. One way is that they can add a user and address on the /dashboard/contacts
page (which also checks for a valid public key!).
See it in action here: https://basicpay.pages.dev/dashboard/contacts
Code implementation
We will create a Svelte store
to keep track of a user's contact list.
Creating the contacts
store
As with the rest of our user-data, the contacts list will live in the browser's localStorage
. We are using the svelt-local-storage-store
package to facilitate this. We create a Svelte store
to hold the data, and add a few custom functions to manage the list: empty
, remove
, add
, favorite
, and lookup
.
This tutorial code is simplified for display here. The code is fully typed, documented, and commented in the source code repository.
import { v4 as uuidv4 } from "uuid";
import { persisted } from "svelte-local-storage-store";
import { StrKey } from "stellar-sdk";
import { error } from "@sveltejs/kit";
import { get } from "svelte/store";
// We are wrapping this store in its own function which will allow us to write
// and customize our own store functions to maintain consistent behavior
// wherever the actions need to take place.
function createContactsStore() {
// Make a `persisted` store that will hold our entire contact list.
const { subscribe, set, update } = persisted("bpa:contactList", []);
return {
subscribe,
// Erases all contact entries from the list and creates a new, empty contact list.
empty: () => set([]),
// Removes the specified contact entry from the list.
remove: (id) =>
update((list) => list.filter((contact) => contact.id !== id)),
// Adds a new contact entry to the list with the provided details.
add: (contact) =>
update((list) => {
if (StrKey.isValidEd25519PublicKey(contact.address)) {
return [...list, { ...contact, id: uuidv4() }];
} else {
throw error(400, { message: "invalid public key" });
}
}),
// Toggles the "favorite" field on the specified contact.
favorite: (id) =>
update((list) => {
const i = list.findIndex((contact) => contact.id === id);
if (i >= 0) {
list[i].favorite = !list[i].favorite;
}
return list;
}),
// Searches the contact list for an entry with the specified address.
lookup: (address) => {
let list = get(contacts);
let i = list.findIndex((contact) => contact.address === address);
if (i >= 0) {
return list[i].name;
} else {
return false;
}
},
};
}
// We export `contacts` as the variable that can be used to interact with the contacts store.
export const contacts = createContactsStore();
Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stores/contactsStore.js
Using the contacts
store
On the /dashboard/contacts
page
We also have a page dedicated to managing contacts. The /dashboard/contacts
page will allow the user to collect and manage a list of contact entries that stores the contact's name and Stellar address. The contact can also be flagged or unflagged as a "favorite" contact to be displayed on the main /dashboard
page.
<script>
// We import things from external packages that will be needed
import { Trash2Icon, UserPlusIcon } from "svelte-feather-icons";
// We import any Svelte components we will need
import TruncatedKey from "$lib/components/TruncatedKey.svelte";
// We import any stores we will need to read and/or write
import { contacts } from "$lib/stores/contactsStore";
// We declare a _reactive_ component variable that will hold information for
// a user-created contact entry, which can be added to the contacts store.
$: newContact = {
name: "",
address: "",
favorite: false,
id: "",
};
</script>
<!-- HTML has been omitted from this tutorial. Please check the source file -->
Source: https://github.com/stellar/basic-payment-app/blob/main/src/routes/dashboard/contacts/+page.svelte
On the /dashboard
page
The contacts
store is now exported from this file and can be accessed and used inside a Svelte page or component. Here is how we've implemented a "favorite contacts" component for display on the main BasicPay dashboard.
<script>
// We import the `contacts` store into our Svelte component
import { contacts } from "$lib/stores/contactsStore";
import TruncatedKey from "$lib/components/TruncatedKey.svelte";
// `$:` makes a Svelte variable reactive, so it will be re-computed any time
// the `$contacts` store is modified. We access a Svelte store by adding `$`
// to the beginning of the variable name.
$: favoriteContacts = $contacts?.filter((contact) => contact.favorite);
</script>
<!-- HTML has been omitted from this tutorial. Please check the source file -->