All files / src/features/Events/EventDetail/host AssignHostModalBody.tsx

93.75% Statements 15/16
90% Branches 9/10
100% Functions 3/3
100% Lines 14/14

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 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103                    1x                                                 1x                         40x 40x 20x         2x                 18x 1x   17x 1x                     16x       95x   95x                           1x      
import { memo } from "react";
import { Box } from "@mui/material";
import { Virtuoso } from "react-virtuoso";
import GiveEmptyStateWrapper from "@shared/EmptyState/GiveEmptyStateWrapper";
import GiveLoadingSpinnerBox from "@shared/GiveLoadingSpinnerBox";
import TechnicalErrorState from "componentsV2/Table/components/TechnicalErrorState";
import AssignHostRow from "./AssignHostRow";
import { AssignableHostRow } from "./host.types";
 
/** The mockup's 4px between rows — on each item, so virtuoso measures it. */
const ROW_GAP = "4px";
 
type Props = {
  isError: boolean;
  isLoading: boolean;
  isListAllowed: boolean;
  /** No hosts on the bench at all, as opposed to a search that matched nothing. */
  isEmpty: boolean;
  rows: AssignableHostRow[];
  search: string;
  onClearSearch: () => void;
  /** The row whose own assign/unassign call is in flight. */
  pendingId: number | null;
  canAssign: boolean;
  onToggle: (row: AssignableHostRow) => void;
};
 
/**
 * The Assign Host modal's content, from the error and permission states down to
 * the bench itself (frames 8181-61190, 8122-59649, 8119-113344).
 *
 * The list is virtualized: `HOST_BENCH_MAX` bounds what the read returns, not
 * what the DOM holds, so a merchant with a long bench mounts only the rows in
 * view. It fills its parent, which therefore has to have a definite height.
 */
const AssignHostModalBody = memo(
  ({
    isError,
    isLoading,
    isListAllowed,
    isEmpty,
    rows,
    search,
    onClearSearch,
    pendingId,
    canAssign,
    onToggle,
  }: Props) => {
    Iif (isError) return <TechnicalErrorState />;
    if (isLoading) return <GiveLoadingSpinnerBox />;
    if (!isListAllowed) {
      // `sectionName` is not optional in practice — the section's copy reads
      // "...access ${sectionName} section", so leaving it off renders the word
      // `undefined` to the merchant. "Host" is the same name the tab's table
      // passes.
      return (
        <GiveEmptyStateWrapper
          isEmpty
          section="not-authorized"
          sectionName="Host"
          noWrapper
        />
      );
    }
    if (isEmpty) {
      return <GiveEmptyStateWrapper isEmpty section="assign-host" noWrapper />;
    }
    if (rows.length === 0) {
      return (
        <GiveEmptyStateWrapper
          isEmpty
          section="assign-host-search"
          searchValue={search}
          action={{ handleAction: onClearSearch }}
          noWrapper
        />
      );
    }
 
    return (
      <Virtuoso
        data={rows}
        style={{ height: "100%" }}
        computeItemKey={(_, row) => row.id}
        itemContent={(_, row) => (
          <Box pb={ROW_GAP}>
            <AssignHostRow
              row={row}
              isPending={pendingId === row.id}
              canAssign={canAssign}
              onToggle={onToggle}
            />
          </Box>
        )}
      />
    );
  },
);
 
AssignHostModalBody.displayName = "AssignHostModalBody";
 
export default AssignHostModalBody;