How can I use the party display name in the React UI?

There are two types for parties:

The Party type is a string, and stands for the party identifier.

The PartyInfo type is an object, which has the following fields:

/**
 * Full information about a Party.
 *
 */
export type PartyInfo = {
  identifier: Party;
  displayName?: string;
  isLocal: boolean;
}

In @daml/react I could only find the useParty hook, which returns the party identifier:

/**
 * React hook to get the party currently connected to the ledger.
 */
export declare function useParty(): Party;

/**
 * The counterpart of Daml's `Party` type.
 *
 * We represent `Party`s as strings matching the regular expression `[A-Za-z0-9:_\- ]+`.
 */
export declare type Party = string;

Is there a way to use the PartyInfo type in the React UI?

1 Like

PartyInfo comes from a specific party-info endpoint in the API. @daml/ledger includes getParties and listKnownParties to interact with it.

3 Likes

The getParties function returns a Promise, so the challenge is to extract a string out of the Promise. Functional languages handle this elegantly with the Result monad and pattern matching.

I couldn’t find the right way for this yet.

This is a way how I tried it, it seems to be correct from a type perspective, the problem is that the useEffect hook doesn’t refresh the state.

import Ledger from '@daml/ledger'

const MainScreen: React.FC<Props> = ({onLogout}) => { 
  const [displayName, setDisplayName] = React.useState("abrakadabra");
  const partyId = useParty();
  useEffect(() => {
    const getDisplayName = async (partyId : string) => {
      let [pInfo, ...rest] = await Ledger.prototype.getParties([partyId]);
      const dName = pInfo?.displayName || partyId;
      setDisplayName(dName);
    } ;
    getDisplayName(partyId)
  }, []);

  return (
    <>
      <Menu icon borderless>
        <Menu.Item>
          <Image
            as='a'
            href='https://www.daml.com/'
            target='_blank'
            src='/daml.svg'
            alt='DAML Logo'
            size='mini'
          />
        </Menu.Item>
        <Menu.Menu position='right' className='test-select-main-menu'>
          <Menu.Item position='right'>
            You are logged in as {displayName}.
          </Menu.Item>
          <Menu.Item
            position='right'
            active={false}
            className='test-select-log-out'
            onClick={onLogout}
            icon='log out'
          />
        </Menu.Menu>
      </Menu>

      <MainView/>
    </>
  );
};
1 Like

Have you tried adding a console.log statement in your hook?

  useEffect(() => {
    const getDisplayName = async (partyId : string) => {
      let [pInfo, ...rest] = await Ledger.prototype.getParties([partyId]);
      console.log(JSON.stringify(pInfo));
      const dName = pInfo?.displayName || partyId;
      setDisplayName(dName);
    } ;
    getDisplayName(partyId)
  }, []);

I can’t see any issue with the code at first glance, but adding that log will answer two important questions:

  1. Does the hook run at all? If not, there’s definitely something wrong somewhere and we need to dig more.
  2. Is the state not refreshing simply due to the value not changing? With displayName being optional, and given the definition of dName, it’s not impossible that you just end up with the party identifier again.
1 Like

It seems that the getParties request doesn’t work, investigating why.

Oh, sorry I missed this yesterday: you’re not supposed to access the prototype directly, you’re supposed to first create a Ledger object and then call getParties on that.

In a React context you probably want to go through the @daml/react library, so initialization would look something like:

import DamlLedger from @daml/react

const App: React.FC = () => {
     <DamlLedger
      token: <your authentication token>
      httpBaseUrl?: <optional http base url>
      wsBaseUrl?: <optional websocket base url>
      reconnectThreshold?: <optional delay in ms>
      party: <the logged in party>
    >
      <MainScreen />
    </DamlLedger>
};

then you can use the useLedger hook to get your hands on a properly initialized Ledger object:

const ledger = useLedger();
useEffect(() => {
    const getDisplayName = async (partyId : string) => {
      // Note here we're using the ledger object, not the
      // prototype from the class
      let [pInfo, ...rest] = await ledger.getParties([partyId]);
      console.log(JSON.stringify(pInfo));
      const dName = pInfo?.displayName || partyId;
      setDisplayName(dName);
    } ;
    getDisplayName(partyId)
  }, []);
1 Like

Perfect, thank you!