A custom hook for using display names in the React UI template

In Daml, a party is represented by an object with three fields: identifier, displayName, and the islocal flag.

In the introductory examples it’s totally fine to use the party identifier in the UI as the representation of Daml parties. The UI template itself uses the identifier field of the Daml party as Party type.

In other cases the party identifier might be too clumsy to display and submit on the demo UI. E.g. in the Daml Hub or Canton, where party identifiers are forced to be long strings.

So with the help of @Stephen, @Gary_Verhaegen, @Mate_Varga and @cocreature, I wrote a custom hook which queries the list of known parties from the ledger, and computes the display name from the party id, and vice versa. We can use these functions to display the display names on the UI, and submit commands using the display name.

As @cocreature pointed out, there is an even more effective way, when the UI doesn’t have to recompute at different levels the same data, using Context. I will come back to this approach some time later, when I have more experience with React.

So this is the code of the custom hook and the way you can use it:

// Usage in components:
// import {useKnownParties} from '../UseKnownParties'
// Within the component:
// const {displayName, partyIdentifier} = useKnownParties () 

import React, { useEffect } from 'react';
import { useLedger, useParty } from '@daml/react';
import Ledger, { PartyInfo } from '@daml/ledger';

export function useKnownParties () {
    const [knownParties, setKnownParties] = React.useState<PartyInfo[]>([]);
    const partyId = useParty();
    const ledger: Ledger = useLedger();

    useEffect(() => {
    const getKnownParties = async () => {
        let lst = await ledger.listKnownParties();
        setKnownParties(lst);
    } ;
    getKnownParties()
    }, [ledger]);

    return {
        displayName : (id: string | undefined): (string | undefined) => {

            if (id === undefined) {
            return id;
            } else {
            return knownParties.filter(x => x.identifier === id)[0]?.displayName
            }},
        partyIdentifier : (displayName: string | undefined): string => {
            let filterResult = knownParties.filter(x => x.displayName === displayName)
            if (filterResult === []) {
                throw new Error("Party display name doesn't exist")
            } else {
                return filterResult[0].identifier
            }
    }

}}

An example from the Create React App for displaying the display name rather the the party id in the MainView component:

import {useKnownParties} from '../UseKnownParties'
...
const {displayName, partyIdentifier} = useKnownParties () 
...
<Header as='h1' size='huge' color='blue' textAlign='center' style={{padding: '1ex 0em 0ex 0em'}}>
    {myUser ? `Welcome, ${displayName(myUser.username)}!` : 'Loading...'}
</Header>

An example for submitting the display name on the UI for exercising the Follow choice, in the PartyListEdit component:

const addParty = async (event?: React.FormEvent) => {
    if (event) {
      event.preventDefault();
    }
    setIsSubmitting(true);
    const success = await onAddParty(partyIdentifier(newParty)); // MODIFIED FOR USING DISPLAY NAME
    setIsSubmitting(false);
    if (success) {
      setNewParty('');
    }
  }
4 Likes

Awesome, looks like you might have the beginnings of a helpful utility library here :slight_smile:

1 Like