This commit is contained in:
Scott Wilson
2025-09-15 10:58:57 -07:00
parent 8fee3c3882
commit 1f4b50a6e0
12 changed files with 269 additions and 104 deletions
@@ -5,7 +5,17 @@ import { AxiosError } from "axios";
import { Button } from "@app/components/v2";
import { ProjectAccessError } from "./components";
export const ErrorPage = ({ error }: ErrorComponentProps) => {
if (
error instanceof AxiosError &&
error.status === 403 &&
error.response?.data?.error === "User not a part of the specified project"
) {
return <ProjectAccessError />;
}
return (
<div className="flex h-screen w-screen items-center justify-center bg-mineshaft-900">
<div className="flex max-w-3xl flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-8 text-center text-mineshaft-200">
@@ -0,0 +1,113 @@
import { faHome } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, useNavigate, useParams } from "@tanstack/react-router";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import { RequestProjectAccessModal } from "@app/components/projects";
import { AccessRestrictedBanner, Button } from "@app/components/v2";
import { OrgPermissionSubjects } from "@app/context";
import { OrgPermissionAdminConsoleAction } from "@app/context/OrgPermissionContext/types";
import { getProjectHomePage } from "@app/helpers/project";
import { usePopUp } from "@app/hooks";
import { useOrgAdminAccessProject, useSearchProjects } from "@app/hooks/api";
export const ProjectAccessError = () => {
const orgAdminAccessProject = useOrgAdminAccessProject();
const navigate = useNavigate();
const { popUp, handlePopUpToggle, handlePopUpOpen } = usePopUp([
"requestAccessConfirmation"
] as const);
const { projectId } = useParams({
strict: false
});
const { data, isPending: isProjectLoading } = useSearchProjects({
projectIds: projectId ? [projectId] : [],
options: {
enabled: Boolean(projectId)
}
});
const [project] = data?.projects ?? [];
const handleAccessProject = async () => {
if (!project) return;
try {
await orgAdminAccessProject.mutateAsync({
projectId: project.id
});
await navigate({
to: getProjectHomePage(project.type, project.environments),
params: {
projectId: project.id
}
});
} catch {
createNotification({
text: "Failed to access project",
type: "error"
});
}
};
return (
<div className="flex h-full w-full items-center justify-center">
<AccessRestrictedBanner
body={
<>
You are not currently a member of this project. Request access to join project.
<div className="mt-4 flex w-full justify-center gap-2">
<Link to="/organization/projects">
<Button variant="outline_bg">
<FontAwesomeIcon icon={faHome} className="mr-2" />
Back To Home
</Button>
</Link>
<OrgPermissionCan
I={OrgPermissionAdminConsoleAction.AccessAllProjects}
an={OrgPermissionSubjects.AdminConsole}
>
{(isAllowed) =>
isAllowed ? (
<Button
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
handleAccessProject();
}}
disabled={orgAdminAccessProject.isPending}
isLoading={isProjectLoading || orgAdminAccessProject.isPending}
>
Join Project as Admin
</Button>
) : (
<Button
onClick={() => handlePopUpOpen("requestAccessConfirmation")}
isLoading={isProjectLoading}
>
Request Access to Project
</Button>
)
}
</OrgPermissionCan>
</div>
<RequestProjectAccessModal
isOpen={popUp.requestAccessConfirmation.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("requestAccessConfirmation", isOpen)}
project={project}
onComplete={() => {
navigate({
to: "/organization/projects"
});
}}
/>
</>
}
/>
</div>
);
};
@@ -0,0 +1 @@
export * from "./ProjectAccessError";