All files / libs/data-capture/fields/components/src/lib/user/selector UserSelector.tsx

100% Statements 82/82
83.33% Branches 5/6
100% Functions 1/1
100% Lines 82/82

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 831x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 120x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 1x 1x  
import { uniqBy } from 'lodash-es';
import { memo, useMemo } from 'react';
import { useIntl } from 'react-intl';
 
import { Select } from '@allshares/studio-design-system';
import { type KeysOfUserWithStringValues, type UserComputed } from '@amalia/tenants/users/types';
 
import { LabelVariant } from '../../types';
import { UserPrettyFormat } from '../pretty-format/UserPrettyFormat';
 
import { type UserOption, type UserSelectOption } from './types';
import { UserSelectorSingleValueLabel } from './UserSelectorSingleValueLabel';
 
export type UserSelectorProps<TProperty extends keyof UserComputed> = {
  /** Users to display in the selector. */
  readonly users: UserOption<TProperty>[];
  /**
   * Selected user's "property" value.
   * For example, the selected user's `"externalId"`.
   */
  readonly value: UserOption<TProperty>[TProperty] | null;
  /** Callback when a user option is selected. */
  readonly onChange: (value: UserOption<TProperty>[TProperty] | null) => void;
  /**
   * Property to use as the value.
   * For example, `"externalId"`
   */
  readonly property: TProperty;
 
  /** Label to display when no user is selected. */
  readonly emptyLabel?: string;
};
 
const UserSelectorBase = function UserSelector<TProperty extends KeysOfUserWithStringValues>({
  users,
  value,
  onChange,
  property,
  emptyLabel,
}: UserSelectorProps<TProperty>) {
  const { formatMessage } = useIntl();
 
  const options = useMemo(
    (): UserSelectOption<TProperty>[] =>
      uniqBy(users, property)
        .map((user) => {
          const optionValue = user[property];
 
          return !!optionValue && !!user.firstName && !!user.lastName
            ? {
                user,
                label: (
                  <UserPrettyFormat
                    firstName={user.firstName}
                    lastName={user.lastName}
                    pictureURL={user.pictureURL}
                    subLabel={optionValue}
                    variant={optionValue === value ? LabelVariant.ACCENTUATED : LabelVariant.DEFAULT}
                  />
                ),
                value: optionValue,
                filterLabel: [user.firstName, user.lastName, user[property]].join(' '),
              }
            : null;
        })
        .filter(Boolean),
    [value, users, property],
  );
 
  return (
    <Select<UserSelectOption<TProperty>>
      isClearable
      options={options}
      placeholder={emptyLabel ?? formatMessage({ defaultMessage: 'No user selected' })}
      SingleValueLabelComponent={UserSelectorSingleValueLabel}
      value={value}
      onChange={onChange}
    />
  );
};
 
export const UserSelector = memo(UserSelectorBase) as typeof UserSelectorBase;