diff --git a/apps/console/src/layouts/EmployeeLayout.tsx b/apps/console/src/layouts/EmployeeLayout.tsx deleted file mode 100644 index d6fe23f6b..000000000 --- a/apps/console/src/layouts/EmployeeLayout.tsx +++ /dev/null @@ -1,402 +0,0 @@ -import { Link, Navigate, Outlet, useParams } from "react-router"; -import { - DropdownSeparator, - IconArrowBoxLeft, - IconCircleQuestionmark, - UserDropdown as UserDropdownRoot, - UserDropdownItem, - Skeleton, - Dropdown, - Button, - DropdownItem, - IconChevronGrabberVertical, - IconLock, - IconKey, - IconPeopleAdd, - IconPlusLarge, - IconCheckmark1, - IconClock, - IconMagnifyingGlass, - useToast, - Logo, - Toasts, - ConfirmDialog, - Avatar, - Badge, - Input, -} from "@probo/ui"; -import { useTranslate } from "@probo/i18n"; -import { graphql } from "relay-runtime"; -import { useLazyLoadQuery } from "react-relay"; -import type { EmployeeLayoutQuery as EmployeeLayoutQueryType } from "./__generated__/EmployeeLayoutQuery.graphql"; -import { Suspense, useState, useEffect, useMemo, use } from "react"; -import { ErrorBoundary } from "react-error-boundary"; -import { PageError } from "/components/PageError"; -import { PermissionsProvider } from "/providers/PermissionsProvider"; -import { PermissionsContext } from "/providers/PermissionsContext"; - -const EmployeeLayoutQuery = graphql` - query EmployeeLayoutQuery($organizationId: ID!) { - viewer { - id - # user { - # fullName - # email - # } - } - organization: node(id: $organizationId) { - ... on Organization { - id - name - logoUrl - } - } - } -`; - -export function EmployeeLayout() { - const { organizationId } = useParams(); - - if (!organizationId) { - return ; - } - - return ( - }> - - - - - ); -} - -function EmployeeLayoutContent({ organizationId }: { organizationId: string }) { - const data = useLazyLoadQuery(EmployeeLayoutQuery, { - organizationId, - }); - - return ( -
-
- - - - -
- -
- }> - - -
-
-
- - - -
-
- - -
- ); -} - -interface Organization { - id: string; - name: string; - logoUrl?: string | null; - authenticationMethod: string; - authStatus: "authenticated" | "unauthenticated" | "expired"; - loginUrl: string; -} - -interface OrganizationsResponse { - organizations: Organization[]; -} - -interface Invitation { - id: string; - email: string; - fullName: string; - role: string; - expiresAt: string; - acceptedAt?: string | null; - createdAt: string; - organization: { - id: string; - name: string; - }; -} - -interface InvitationsResponse { - invitations: Invitation[]; -} - -function OrganizationSelector({ - currentOrganization, -}: { - currentOrganization: EmployeeLayoutQueryType["response"]["organization"]; -}) { - const [organizations, setOrganizations] = useState([]); - const [pendingInvitationsCount, setPendingInvitationsCount] = useState(0); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - const [search, setSearch] = useState(""); - const { __ } = useTranslate(); - - const filteredOrganizations = useMemo(() => { - if (!search.trim()) { - return organizations; - } - return organizations.filter((org) => - org.name.toLowerCase().includes(search.toLowerCase()) - ); - }, [organizations, search]); - - useEffect(() => { - const fetchData = async () => { - try { - setIsLoading(true); - - const [orgsResponse, invitationsResponse] = await Promise.all([ - fetch("/connect/organizations", { credentials: "include" }), - fetch("/connect/invitations", { credentials: "include" }), - ]); - - if (!orgsResponse.ok) { - throw new Error("Failed to fetch organizations"); - } - - if (!invitationsResponse.ok) { - throw new Error("Failed to fetch invitations"); - } - - const orgsData: OrganizationsResponse = await orgsResponse.json(); - const invitationsData: InvitationsResponse = - await invitationsResponse.json(); - - const pendingCount = invitationsData.invitations.filter( - (inv) => !inv.acceptedAt - ).length; - - setOrganizations(orgsData.organizations); - setPendingInvitationsCount(pendingCount); - setError(null); - } catch (err) { - setError(err instanceof Error ? err.message : "Unknown error"); - console.error("Failed to fetch data:", err); - } finally { - setIsLoading(false); - } - }; - - fetchData(); - }, []); - - if (error) { - return ( -
- -
- ); - } - - return ( -
- - {isLoading ? __("Loading...") : currentOrganization?.name || ""} - - } - > - {!isLoading && organizations.length > 0 && ( -
- { - e.stopPropagation(); - }} - autoFocus - /> -
- )} -
- {isLoading ? ( -
- {__("Loading organizations...")} -
- ) : filteredOrganizations.length === 0 ? ( -
- {__("No organizations found")} -
- ) : ( - filteredOrganizations.map((organization) => { - const isAuthenticated = - organization.authStatus === "authenticated"; - const isExpired = organization.authStatus === "expired"; - const needsAuth = organization.authStatus === "unauthenticated"; - - const targetUrl = isAuthenticated - ? `/organizations/${organization.id}` - : organization.loginUrl; - - const isSAMLUrl = targetUrl.includes("/connect/saml/"); - - const logoUrl = organization.logoUrl; - - return ( - - {isSAMLUrl ? ( - - - {organization.name} - {isAuthenticated && ( - - )} - {isExpired && ( - - )} - {needsAuth && ( - - )} - - ) : ( - - - {organization.name} - {isAuthenticated && ( - - )} - {isExpired && ( - - )} - {needsAuth && ( - - )} - - )} - - ); - }) - )} -
- - {pendingInvitationsCount > 0 && ( - - - - {__("Invitations")} - - {pendingInvitationsCount} - - - - )} - - - - {__("Add organization")} - - -
- {pendingInvitationsCount > 0 && ( - -
- ); -} - -function UserDropdown() { - const { __ } = useTranslate(); - const { toast } = useToast(); - const { isAuthorized } = use(PermissionsContext); - const user = { - fullName: "", - email: "", - }; - // const user = useLazyLoadQuery(EmployeeLayoutQuery, { - // organizationId, - // }).viewer.user; - - const handleLogout: React.MouseEventHandler = async ( - e - ) => { - e.preventDefault(); - - fetch("/connect/logout", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({}), - }) - .then(async (res) => { - if (!res.ok) { - const error = await res.json(); - throw new Error(error.message || __("Failed to login")); - } - - window.location.reload(); - }) - .catch((e) => { - toast({ - title: __("Error"), - description: e.message as string, - variant: "error", - }); - }); - }; - - return ( - - {isAuthorized("Organization", "deleteOrganization") && ( - - )} - - - - - ); -} diff --git a/apps/console/src/pages/organizations/employee/EmployeeDocumentsPage.tsx b/apps/console/src/pages/organizations/employee/EmployeeDocumentsPage.tsx index 54a12fbb5..88c4e4b14 100644 --- a/apps/console/src/pages/organizations/employee/EmployeeDocumentsPage.tsx +++ b/apps/console/src/pages/organizations/employee/EmployeeDocumentsPage.tsx @@ -28,20 +28,18 @@ export const employeeDocumentsPageQuery = graphql` export function EmployeeDocumentsPage(props: { queryRef: PreloadedQuery; }) { + const { queryRef } = props; const { __ } = useTranslate(); const organizationId = useOrganizationId(); - const { queryRef } = props; const { - viewer: { - signableDocuments: { edges: initialDocuments }, - }, + viewer: { signableDocuments }, } = usePreloadedQuery( employeeDocumentsPageQuery, queryRef ); - const documents = initialDocuments.map((edge) => edge.node).filter(Boolean); + const documents = signableDocuments.edges.map((edge) => edge.node); usePageTitle(__("Documents")); diff --git a/apps/console/src/pages/organizations/employee/EmployeeDocumentsPageLoader.tsx b/apps/console/src/pages/organizations/employee/EmployeeDocumentsPageLoader.tsx index 6f1ce62ac..4eef2980b 100644 --- a/apps/console/src/pages/organizations/employee/EmployeeDocumentsPageLoader.tsx +++ b/apps/console/src/pages/organizations/employee/EmployeeDocumentsPageLoader.tsx @@ -22,20 +22,18 @@ function EmployeeDocumentsPageLoader() { }, [loadQuery, organizationId]); if (!queryRef) { - return ; + return null; } - return ( - }> - - - ); + return ; } export default function () { return ( - + }> + + ); } diff --git a/apps/console/src/pages/organizations/settings/DomainSettingsPage.tsx b/apps/console/src/pages/organizations/settings/DomainSettingsPage.tsx index c733129da..adeabd1aa 100644 --- a/apps/console/src/pages/organizations/settings/DomainSettingsPage.tsx +++ b/apps/console/src/pages/organizations/settings/DomainSettingsPage.tsx @@ -30,7 +30,7 @@ export function DomainSettingsPage(props: { const { organization } = usePreloadedQuery( domainSettingsPageQuery, - queryRef, + queryRef ); if (organization.__typename !== "Organization") { throw new Error("invalid type for node"); @@ -49,7 +49,7 @@ export function DomainSettingsPage(props: {

{__( - "Add your own domain to make your trust center more professional", + "Add your own domain to make your trust center more professional" )}

diff --git a/apps/console/src/routes.tsx b/apps/console/src/routes.tsx index 55f0bb421..225dde20d 100644 --- a/apps/console/src/routes.tsx +++ b/apps/console/src/routes.tsx @@ -4,7 +4,6 @@ import { redirect, useRouteError, } from "react-router"; -import { EmployeeLayout } from "./layouts/EmployeeLayout.tsx"; import { CenteredLayout, CenteredLayoutSkeleton } from "@probo/ui"; import { PageSkeleton } from "./components/skeletons/PageSkeleton.tsx"; import { riskRoutes } from "./routes/riskRoutes.ts"; @@ -27,7 +26,6 @@ import { continualImprovementRoutes } from "./routes/continualImprovementRoutes. import { rightsRequestRoutes } from "./routes/rightsRequestRoutes.ts"; import { processingActivityRoutes } from "./routes/processingActivityRoutes.ts"; import { statesOfApplicabilityRoutes } from "./routes/statesOfApplicabilityRoutes.ts"; -import { CoreRelayProvider } from "./providers/CoreRelayProvider.tsx"; import { lazy } from "@probo/react-lazy"; import { routeFromAppRoute, type AppRoute } from "@probo/routes"; import { Role } from "@probo/helpers"; @@ -121,15 +119,15 @@ const routes = [ }, { path: "/organizations/:organizationId/employee", - Component: () => ( - - - + Fallback: () => "fallback employee...", + Component: lazy( + () => import("./pages/iam/memberships/MembershipLayoutLoader") ), ErrorBoundary: ErrorBoundary, children: [ { - path: "", + index: true, + // Component: () => "hello world", Component: lazy( () => import("./pages/organizations/employee/EmployeeDocumentsPageLoader")