Create assume page to redirect to when AssumptionRequired catched in boundary
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -15,7 +15,7 @@ export function OrganizationErrorBoundary() {
|
||||
}
|
||||
|
||||
if (error instanceof AssumptionRequiredError) {
|
||||
return <Navigate to="/auth/login" state={{ from: location.pathname, organizationId }} />;
|
||||
return <Navigate to={`/organizations/${organizationId}/assume`} state={{ from: location.pathname }} />;
|
||||
}
|
||||
|
||||
return <PageError error={error instanceof Error ? error : new Error("unknown error")} />;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { Card, Logo } from "@probo/ui";
|
||||
import type { PropsWithChildren } from "react";
|
||||
import { Outlet } from "react-router";
|
||||
|
||||
import { IAMRelayProvider } from "#/providers/IAMRelayProvider";
|
||||
|
||||
export default function AuthLayout() {
|
||||
export default function AuthLayout(props: PropsWithChildren) {
|
||||
const { children } = props;
|
||||
|
||||
return (
|
||||
<div className="min-h-screen text-txt-primary bg-level-0 flex flex-col items-center justify-center">
|
||||
<Card className="w-full max-w-lg px-12 py-8 flex flex-col items-center justify-center">
|
||||
@@ -12,7 +15,7 @@ export default function AuthLayout() {
|
||||
<div className="w-full border-t border-t-border-mid" />
|
||||
</div>
|
||||
<IAMRelayProvider>
|
||||
<Outlet />
|
||||
{children ?? <Outlet />}
|
||||
</IAMRelayProvider>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
35
apps/console/src/pages/iam/organizations/AssumePage.tsx
Normal file
35
apps/console/src/pages/iam/organizations/AssumePage.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import { useLocation, useNavigate } from "react-router";
|
||||
|
||||
import { useAssume } from "#/hooks/iam/useAssume";
|
||||
|
||||
import AuthLayout from "../auth/AuthLayout";
|
||||
|
||||
interface State {
|
||||
from: string;
|
||||
}
|
||||
|
||||
export default function AssumePage() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const state = location.state as State;
|
||||
|
||||
const { __ } = useTranslate();
|
||||
|
||||
useAssume({
|
||||
onSuccess: () => void navigate(state.from),
|
||||
});
|
||||
|
||||
return (
|
||||
<AuthLayout>
|
||||
<div className="space-y-6 w-full max-w-md mx-auto pt-8">
|
||||
<div className="space-y-2 text-center">
|
||||
<h1 className="text-3xl font-bold">{__("Sign in Redirection")}</h1>
|
||||
<p className="text-txt-tertiary">
|
||||
{__("Redirecting you to your authentication URL…")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</AuthLayout>
|
||||
);
|
||||
}
|
||||
@@ -120,119 +120,127 @@ const routes = [
|
||||
() => import("./pages/DocumentSigningRequestsPage"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "/organizations/:organizationId/employee",
|
||||
Component: lazy(
|
||||
() => import("./pages/organizations/employee/EmployeeLayoutLoader"),
|
||||
),
|
||||
ErrorBoundary: OrganizationErrorBoundary,
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/organizations/employee/EmployeeDocumentsPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: ":documentId",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/organizations/employee/EmployeeDocumentSignaturePageLoader"),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/organizations/:organizationId",
|
||||
Component: lazy(
|
||||
() => import("./pages/iam/organizations/ViewerMembershipLayoutLoader"),
|
||||
),
|
||||
ErrorBoundary: OrganizationErrorBoundary,
|
||||
children: [
|
||||
{
|
||||
path: "",
|
||||
Component: () => {
|
||||
const { role } = use(CurrentUser);
|
||||
switch (role) {
|
||||
case Role.EMPLOYEE:
|
||||
return <Navigate to="employee" />;
|
||||
case Role.AUDITOR:
|
||||
return <Navigate to="measures" />;
|
||||
default:
|
||||
return <Navigate to="tasks" />;
|
||||
}
|
||||
},
|
||||
path: "assume",
|
||||
Component: lazy(() => import("./pages/iam/organizations/AssumePage")),
|
||||
},
|
||||
{
|
||||
path: "settings",
|
||||
Fallback: PageSkeleton,
|
||||
path: "employee",
|
||||
Component: lazy(
|
||||
() => import("./pages/iam/organizations/settings/SettingsLayout"),
|
||||
() => import("./pages/organizations/employee/EmployeeLayoutLoader"),
|
||||
),
|
||||
ErrorBoundary: OrganizationErrorBoundary,
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
loader: () => {
|
||||
// eslint-disable-next-line
|
||||
throw redirect("general");
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "general",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/GeneralSettingsPageLoader"),
|
||||
import("./pages/organizations/employee/EmployeeDocumentsPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "members",
|
||||
path: ":documentId",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/MembersPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "saml-sso",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/SAMLSettingsPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "scim",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/SCIMSettingsPageLoader"),
|
||||
import("./pages/organizations/employee/EmployeeDocumentSignaturePageLoader"),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
...riskRoutes,
|
||||
...measureRoutes,
|
||||
...documentsRoutes,
|
||||
...peopleRoutes,
|
||||
...vendorRoutes,
|
||||
...frameworkRoutes,
|
||||
...taskRoutes,
|
||||
...assetRoutes,
|
||||
...dataRoutes,
|
||||
...auditRoutes,
|
||||
...meetingsRoutes,
|
||||
...nonconformityRoutes,
|
||||
...obligationRoutes,
|
||||
...continualImprovementRoutes,
|
||||
...rightsRequestRoutes,
|
||||
...processingActivityRoutes,
|
||||
...statesOfApplicabilityRoutes,
|
||||
...compliancePageRoutes,
|
||||
...snapshotsRoutes,
|
||||
{
|
||||
path: "*",
|
||||
Component: PageError,
|
||||
Component: lazy(
|
||||
() => import("./pages/iam/organizations/ViewerMembershipLayoutLoader"),
|
||||
),
|
||||
ErrorBoundary: OrganizationErrorBoundary,
|
||||
children: [
|
||||
{
|
||||
Component: () => {
|
||||
const { role } = use(CurrentUser);
|
||||
switch (role) {
|
||||
case Role.EMPLOYEE:
|
||||
return <Navigate to="employee" />;
|
||||
case Role.AUDITOR:
|
||||
return <Navigate to="measures" />;
|
||||
default:
|
||||
return <Navigate to="tasks" />;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "settings",
|
||||
Fallback: PageSkeleton,
|
||||
Component: lazy(
|
||||
() => import("./pages/iam/organizations/settings/SettingsLayout"),
|
||||
),
|
||||
children: [
|
||||
{
|
||||
index: true,
|
||||
loader: () => {
|
||||
// eslint-disable-next-line
|
||||
throw redirect("general");
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "general",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/GeneralSettingsPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "members",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/MembersPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "saml-sso",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/SAMLSettingsPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "scim",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/SCIMSettingsPageLoader"),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
...riskRoutes,
|
||||
...measureRoutes,
|
||||
...documentsRoutes,
|
||||
...peopleRoutes,
|
||||
...vendorRoutes,
|
||||
...frameworkRoutes,
|
||||
...taskRoutes,
|
||||
...assetRoutes,
|
||||
...dataRoutes,
|
||||
...auditRoutes,
|
||||
...meetingsRoutes,
|
||||
...nonconformityRoutes,
|
||||
...obligationRoutes,
|
||||
...continualImprovementRoutes,
|
||||
...rightsRequestRoutes,
|
||||
...processingActivityRoutes,
|
||||
...statesOfApplicabilityRoutes,
|
||||
...compliancePageRoutes,
|
||||
...snapshotsRoutes,
|
||||
{
|
||||
path: "*",
|
||||
Component: PageError,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Fallback URL to the NotFound Page
|
||||
{
|
||||
path: "*",
|
||||
|
||||
@@ -410,13 +410,9 @@ func (r *mutationResolver) SignIn(ctx context.Context, input types.SignInInput)
|
||||
var err error
|
||||
session, _, err = r.iam.SessionService.OpenPasswordChildSessionForOrganization(ctx, session.ID, *input.OrganizationID)
|
||||
if err != nil {
|
||||
var errSessionExpired *iam.ErrSessionExpired
|
||||
var errMembershipNotFound *iam.ErrMembershipNotFound
|
||||
var errMembershipInactive *iam.ErrMembershipInactive
|
||||
|
||||
if errors.As(err, errSessionExpired) {
|
||||
return nil, gqlutils.Unauthenticated(ctx, err)
|
||||
}
|
||||
if errors.As(err, errMembershipNotFound) || errors.As(err, errMembershipInactive) {
|
||||
return nil, gqlutils.Forbidden(ctx, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user