All files / app/components UsersList.tsx

100% Statements 21/21
94.44% Branches 17/18
100% Functions 7/7
100% Lines 19/19

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 83 84 85 86 8710x 10x 10x       10x   190x       121x                                           211x                   190x       190x 290x   190x 190x   185x   185x 44x 141x       94x       96x       156x                                
import { CircularProgress, styled } from "@mui/material";
import UserSummary from "components/UserSummary";
import { useLiteUsers } from "features/userQueries/useLiteUsers";
import { RpcError } from "grpc-web";
import { ReactNode } from "react";
 
import Alert from "./Alert";
 
const ContainingDiv = styled("div")(({ theme }) => ({
  padding: theme.spacing(2),
}));
 
const StyledUsersDiv = styled("div")(({ theme }) => ({
  display: "grid",
  marginBlockStart: theme.spacing(2),
  rowGap: theme.spacing(1),
}));
 
export interface UsersListProps {
  userIds: number[] | undefined;
  emptyListChildren?: ReactNode;
  endChildren?: ReactNode;
  error?: RpcError | null;
}
 
/**
 * A cute list of <UserSummary> components for each userId. Automatically fetches the user info.
 *
 * A spinner shows up while `userIds` is `undefined`. When this component is fetching the lite users, it will show skeletons (the right number).
 *
 * If any users are not found or userIds is an empty list, this will show `emptyListChildren`.
 *
 * The end of the list will show `endChildren` if the list is not empty (this is a good place to add a "load more" button)
 */
export default function UsersList({
  userIds,
  emptyListChildren,
  endChildren,
  error,
}: UsersListProps) {
  const {
    data: users,
    isLoading: isLoadingLiteUsers,
    error: usersError,
  } = useLiteUsers(userIds || []);
 
  // this is undefined if userIds is undefined or users hasn't loaded, otherwise it's an actual list
  const foundUserIds: number[] | undefined =
    userIds &&
    (userIds.length > 0 ? userIds?.filter((userId) => users?.has(userId)) : []);
 
  const inner = () => {
    if (error) {
      return <Alert severity="error">{error.message}</Alert>;
    } else Iif (usersError) {
      return <Alert severity="error">{usersError.message}</Alert>;
    } else if (!userIds) {
      return <CircularProgress />;
    } else if (isLoadingLiteUsers) {
      return (
        <StyledUsersDiv>
          {userIds.map((userId) => (
            <UserSummary headlineComponent="h3" key={userId} user={undefined} />
          ))}
        </StyledUsersDiv>
      );
    } else if (foundUserIds && foundUserIds.length > 0) {
      return (
        <StyledUsersDiv>
          {foundUserIds.map((userId) => (
            <UserSummary
              headlineComponent="h3"
              key={userId}
              user={users?.get(userId)}
            />
          ))}
          <>{endChildren}</>
        </StyledUsersDiv>
      );
    } else {
      return <>{emptyListChildren}</>;
    }
  };
 
  return <ContainingDiv>{inner()}</ContainingDiv>;
}