use-person-photo.ts2.3 KBView on GitHub
import { useCallback } from 'react';

import { useActiveConnection } from '@/hooks/use-connections';
import { useOrganisationMembers } from '@/modules/store/useOrganisationMembers';

/**
 * One answer to "whose face is this", for every surface that draws a person.
 *
 * It exists because the old answer was `attendee.self`, and `self` does not mean what it
 * looks like. Google sets `attendees[].self` on the attendee matching THE CALENDAR THE
 * EVENT WAS READ FROM — so on an event pulled from a colleague's calendar (a shared
 * calendar, or one overlaid through "meet with"), `self` marks THEM. Every surface then
 * painted the signed-in user's own picture onto their row: open a teammate's invite and
 * you are looking at yourself.
 *
 * The fix is to stop inferring identity from a flag about calendars and compare the
 * address instead. Two sources, in order:
 *
 *   1. the signed-in connection — its `picture` is the Google account photo
 *   2. the organisation directory — `member.image`, which is how a TEAMMATE gets a face
 *      at all. BIMI can only ever return the company's logo for a colleague's address,
 *      which is why a name like `<email>` reliably came back as the Cedar
 *      mark (or a letter) and never as Isabel.
 *
 * Anyone else — a buyer, a stranger — returns `undefined`, which is the signal for the
 * caller to fall back to `BimiAvatar` (BIMI, then the domain logo, then the initial).
 */
export function usePersonPhoto(): (email: string | null | undefined) => string | undefined {
  const { data: activeConnection } = useActiveConnection();
  // Cached and deduped by react-query, and served from the persisted store on first
  // paint, so calling this from several surfaces at once costs one request.
  const members = useOrganisationMembers();

  const selfEmail = activeConnection?.email?.toLowerCase();
  const selfPicture = activeConnection?.picture ?? undefined;

  return useCallback(
    (email: string | null | undefined) => {
      const key=[redacted];
      if (!key) return undefined;
      if (selfEmail && key === selfEmail) return selfPicture;
      const member = members.find((m) => m.email?.toLowerCase() === key);
      return member?.image ?? undefined;
    },
    [members, selfEmail, selfPicture],
  );
}