diff --git a/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx b/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx index d75576ccfe..c7607c4e6d 100644 --- a/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx +++ b/packages/cpt-ui/src/components/EpsRoleSelectionPage.tsx @@ -11,6 +11,8 @@ import { Card } from "nhsuk-react-components" +import "../styles/roleselectionpage.scss" + import {useAuth} from "@/context/AuthProvider" import {RoleDetails} from "@cpt-ui-common/common-types" import {Button} from "./ReactRouterButton" @@ -96,6 +98,8 @@ export default function RoleSelectionPage({ const navigate = useNavigate() const redirecting = useRef(false) + const [isSelectingRole, setIsSelectingRole] = useState(false) + const [selectedCardId, setSelectedCardId] = useState(null) const [roleComponentProps, setRoleComponentProps] = useState({ rolesWithAccess: [], @@ -111,6 +115,15 @@ export default function RoleSelectionPage({ roleCardProps: RolesWithAccessProps ) => { e.preventDefault() + + // Prevent multiple submissions + if (isSelectingRole) { + return + } + + setIsSelectingRole(true) + setSelectedCardId(roleCardProps.uuid) + try { await auth.updateSelectedRole(roleCardProps.role) navigate(roleCardProps.link) @@ -121,6 +134,8 @@ export default function RoleSelectionPage({ return } logger.error("Error selecting role:", err) + setIsSelectingRole(false) // Reset loading state on error + setSelectedCardId(null) } } @@ -330,6 +345,7 @@ export default function RoleSelectionPage({ @@ -342,44 +358,85 @@ export default function RoleSelectionPage({
{roleComponentProps.rolesWithAccess - .map((roleCardProps: RolesWithAccessProps) => ( - handleCardKeyDown(e, roleCardProps)} - onClick={(e) => handleCardClick(e, roleCardProps)} - style={{cursor: "pointer"}} - > - -
-
- - {roleCardProps.role.org_name || noOrgName} -
- (ODS: {roleCardProps.role.org_code || noODSCode}) -
- - {roleCardProps.role.role_name || noRoleName} - -
-
- - {(roleCardProps.role.site_address || contentText.noAddress) - .split("\n") - .map((line: string, index: number) => ( - - {line} -
-
- ))} -
+ .map((roleCardProps: RolesWithAccessProps) => { + const isThisCardSelected = selectedCardId === roleCardProps.uuid + const isOtherCardDisabled = isSelectingRole && !isThisCardSelected + + return ( + handleCardKeyDown(e, roleCardProps)} + onClick={isOtherCardDisabled ? undefined : (e) => handleCardClick(e, roleCardProps)} + style={{ + cursor: isOtherCardDisabled ? "not-allowed" : "pointer", + opacity: isOtherCardDisabled ? 0.5 : 1, + pointerEvents: isOtherCardDisabled ? "none" : "auto" + }} + role="button" + aria-disabled={isOtherCardDisabled} + > + +
+ +
+ + {(roleCardProps.role.site_address || contentText.noAddress) + .split("\n") + .map((line: string, index: number) => ( + + {line} +
+
+ ))} +
+
-
- - - ))} + + + ) + })}
)} diff --git a/packages/cpt-ui/src/components/ReactRouterButton.tsx b/packages/cpt-ui/src/components/ReactRouterButton.tsx index 8e19ef4983..b44d0e5534 100644 --- a/packages/cpt-ui/src/components/ReactRouterButton.tsx +++ b/packages/cpt-ui/src/components/ReactRouterButton.tsx @@ -18,7 +18,6 @@ interface ReactRouterButtonProps extends React.ButtonHTMLAttributes = ({ children, to, - // eslint-disable-next-line @typescript-eslint/no-unused-vars disabled = false, onClick, className = "", @@ -28,6 +27,11 @@ export const Button: React.FC = ({ const navigate = useNavigate() const handleClick = (event: React.MouseEvent | React.KeyboardEvent) => { + if (disabled) { + event.preventDefault() + return + } + if (to) { event.preventDefault() const absolutePath = to.startsWith("/") ? to : `/${to}` @@ -40,6 +44,7 @@ export const Button: React.FC = ({ return (