All files / react-app/src/features/sign-up stateRoleSignup.tsx

95.45% Statements 21/22
70% Branches 7/10
85.71% Functions 6/7
95.23% Lines 20/21

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 104 105 106 107 108 109 110 111 112 113 114 115 116                                                  2x 8x 8x   8x 8x   8x   8x 8x 8x   8x   8x   8x                               8x 8x 16x 16x 16x   16x               3x                                           2x                                          
import { ChevronLeft } from "lucide-react";
import { useMemo } from "react";
import { Navigate, useNavigate, useSearchParams } from "react-router";
import { StateCode } from "shared-types";
import { UserRole } from "shared-types/events/legacy-user";
import { isStateRole } from "shared-utils";
 
import { useGetUserDetails, useGetUserProfile, UserDetails, useStateAccessMap } from "@/api";
import {
  LoadingSpinner,
  OptionCard,
  OptionFieldset,
  SimplePageContainer,
  SubNavHeader,
} from "@/components";
import { useFeatureFlag } from "@/hooks/useFeatureFlag";
import { convertStateAbbrToFullName } from "@/utils";
 
type RoleOptions = {
  key: UserRole;
  title: string;
  description: string;
  link: string;
};
 
export const StateRoleSignup = () => {
  const isNewUserRoleDisplay = useFeatureFlag("SHOW_USER_ROLE_UPDATE");
  const navigate = useNavigate();
 
  const [searchParams] = useSearchParams();
  const statesParam = searchParams.get("states") as StateCode;
 
  const statesRequested = useMemo(() => statesParam?.split(",") ?? [], [statesParam]);
 
  const { data, isLoading: isUserDetailsLoading } = useGetUserDetails();
  const userDetails = data as UserDetails | null;
  const { data: userProfile } = useGetUserProfile();
 
  const stateAccessMap = useStateAccessMap(userProfile?.stateAccess);
 
  const encodedStatesQuery = encodeURIComponent(statesParam ?? "");
 
  const roleOptions = [
    {
      key: "statesubmitter",
      title: "State Submitter",
      description: "Responsible for submitting packages",
      link: `/signup/state/role/confirm?role=statesubmitter&states=${encodedStatesQuery}`,
    },
    {
      key: "statesystemadmin",
      title: "State System Administrator",
      description: "Ability to approve state submitters and submit packages",
      link: `/signup/state/role/confirm?role=statesystemadmin&states=${encodedStatesQuery}`,
    },
  ] satisfies RoleOptions[];
 
  // Filter out role(s) if it already exists for every selected state
  const filteredRoleOptions = useMemo(() => {
    return roleOptions.filter((roleOption) => {
      const hasRoleInAllStates = statesRequested.every((state) => {
        const rolesForState = stateAccessMap[state];
        return rolesForState?.has(roleOption.key as UserRole);
      });
      return !hasRoleInAllStates;
    });
  }, [roleOptions, statesRequested, stateAccessMap]);
 
  if (!isNewUserRoleDisplay) return <Navigate to="/signup" replace />;
  if (!statesParam) return <Navigate to="/signup/state" />;
  if (isUserDetailsLoading) return <LoadingSpinner />;
  if (!userDetails) return <Navigate to="/" />;
  if (userDetails.role && !isStateRole(userDetails.role)) {
    return <Navigate to="/profile" />;
  }
 
  return (
    <div>
      <SubNavHeader>
        <div className="flex items-center">
          <ChevronLeft
            className="text-sky-700 w-6 h-6 mr-2 cursor-pointer"
            onClick={() => navigate("/signup/state")}
          />
          <h1 className="text-xl font-medium">Select A Role</h1>
        </div>
      </SubNavHeader>
      <SimplePageContainer>
        <section className="max-w-3xl mx-auto">
          <div className="py-10">
            <h2 className="text-xl font-bold">
              {statesRequested.length > 1 ? "States / Territories:" : "State / Territory:"}
            </h2>
            <p className="text-xl italic">
              {statesRequested.map((state) => convertStateAbbrToFullName(state)).join(", ")}
            </p>
          </div>
          <div className="pb-10">
            <h2 className="text-xl font-bold">Available roles to add</h2>
            <OptionFieldset>
              {filteredRoleOptions.map((role) => (
                <OptionCard
                  description={role.description}
                  title={role.title}
                  to={role.link}
                  key={role.key}
                />
              ))}
            </OptionFieldset>
          </div>
        </section>
      </SimplePageContainer>
    </div>
  );
};