From bb4876fd4fe6026ba15d09f35d67a5fc18410515 Mon Sep 17 00:00:00 2001 From: manish-singh-bisht Date: Sat, 13 Dec 2025 21:36:24 +0530 Subject: [PATCH] improvement:frontend search filter on organizations Signed-off-by: manish-singh-bisht --- apps/console/src/layouts/EmployeeLayout.tsx | 32 +++++++++++++-- apps/console/src/layouts/MainLayout.tsx | 32 +++++++++++++-- apps/console/src/pages/OrganizationsPage.tsx | 42 ++++++++++++++++---- 3 files changed, 92 insertions(+), 14 deletions(-) diff --git a/apps/console/src/layouts/EmployeeLayout.tsx b/apps/console/src/layouts/EmployeeLayout.tsx index fdb65ac8e..6fe03e929 100644 --- a/apps/console/src/layouts/EmployeeLayout.tsx +++ b/apps/console/src/layouts/EmployeeLayout.tsx @@ -16,18 +16,20 @@ import { 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, use } from "react"; +import { Suspense, useState, useEffect, useMemo, use } from "react"; import { ErrorBoundary } from "react-error-boundary"; import { PageError } from "/components/PageError"; import { buildEndpoint } from "/providers/RelayProviders"; @@ -152,8 +154,18 @@ function OrganizationSelector({ 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 { @@ -218,17 +230,31 @@ function OrganizationSelector({ } > + {!isLoading && organizations.length > 0 && ( +
+ { + e.stopPropagation(); + }} + autoFocus + /> +
+ )}
{isLoading ? (
{__("Loading organizations...")}
- ) : organizations.length === 0 ? ( + ) : filteredOrganizations.length === 0 ? (
{__("No organizations found")}
) : ( - organizations.map((organization) => { + filteredOrganizations.map((organization) => { const isAuthenticated = organization.authStatus === "authenticated"; const isExpired = organization.authStatus === "expired"; diff --git a/apps/console/src/layouts/MainLayout.tsx b/apps/console/src/layouts/MainLayout.tsx index 816de3049..6135c11b5 100644 --- a/apps/console/src/layouts/MainLayout.tsx +++ b/apps/console/src/layouts/MainLayout.tsx @@ -23,6 +23,7 @@ import { IconKey, IconListStack, IconLock, + IconMagnifyingGlass, IconMedal, IconPageTextLine, IconPeopleAdd, @@ -32,6 +33,7 @@ import { IconShield, IconStore, IconTodo, + Input, Layout, SidebarItem, Skeleton, @@ -39,7 +41,7 @@ import { UserDropdown as UserDropdownRoot, useToast, } from "@probo/ui"; -import { Suspense, use, useEffect, useState } from "react"; +import { Suspense, use, useEffect, useMemo, useState } from "react"; import { ErrorBoundary } from "react-error-boundary"; import { useLazyLoadQuery } from "react-relay"; import { Link, Navigate, Outlet, useParams } from "react-router"; @@ -364,8 +366,18 @@ function OrganizationSelector({ 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 { @@ -429,18 +441,30 @@ function OrganizationSelector({ {isLoading ? __("Loading...") : currentOrganization?.name || ""} } - > + > +
+ { + e.stopPropagation(); + }} + autoFocus + /> +
{isLoading ? (
{__("Loading organizations...")}
- ) : organizations.length === 0 ? ( + ) : filteredOrganizations.length === 0 ? (
{__("No organizations found")}
) : ( - organizations.map((organization) => { + filteredOrganizations.map((organization) => { const isAuthenticated = organization.authStatus === "authenticated"; const isExpired = organization.authStatus === "expired"; diff --git a/apps/console/src/pages/OrganizationsPage.tsx b/apps/console/src/pages/OrganizationsPage.tsx index ad9c4fe5b..6c78df177 100644 --- a/apps/console/src/pages/OrganizationsPage.tsx +++ b/apps/console/src/pages/OrganizationsPage.tsx @@ -1,5 +1,5 @@ import { useTranslate } from "@probo/i18n"; -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Link, useNavigate } from "react-router"; import { Avatar, @@ -9,7 +9,9 @@ import { IconCheckmark1, IconLock, IconClock, + IconMagnifyingGlass, Badge, + Input, } from "@probo/ui"; import { usePageTitle } from "@probo/hooks"; import { formatDate } from "@probo/helpers"; @@ -46,6 +48,16 @@ export default function OrganizationsPage() { const [invitations, setInvitations] = useState([]); const [isLoadingInvitations, setIsLoadingInvitations] = useState(true); const [isAccepting, setIsAccepting] = useState(false); + const [search, setSearch] = useState(""); + + const filteredOrganizations = useMemo(() => { + if (!search.trim()) { + return organizations; + } + return organizations.filter((org) => + org.name.toLowerCase().includes(search.toLowerCase()) + ); + }, [organizations, search]); // Fetch organizations from REST endpoint useEffect(() => { @@ -163,12 +175,28 @@ export default function OrganizationsPage() { {__("Your organizations")} )} - {organizations.map((organization) => ( - - ))} + {organizations.length > 3 && ( +
+ +
+ )} + {filteredOrganizations.length === 0 ? ( +
+ {__("No organizations found")} +
+ ) : ( + filteredOrganizations.map((organization) => ( + + )) + )}
)}