diff --git a/CHANGELOG.md b/CHANGELOG.md index 133fd727a..d212d2aa1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#645](https://github.com/alleslabs/celatone-frontend/pull/645) Add search for resource in account detail +- [#634](https://github.com/alleslabs/celatone-frontend/pull/634) api v1 - move pool info - [#657](https://github.com/alleslabs/celatone-frontend/pull/657) api v1 - overview stats - [#650](https://github.com/alleslabs/celatone-frontend/pull/650) api v1 - account info on account detail page - [#655](https://github.com/alleslabs/celatone-frontend/pull/655) Change title of publish new module page diff --git a/src/lib/app-provider/hooks/useBaseApiRoute.ts b/src/lib/app-provider/hooks/useBaseApiRoute.ts index dfb270ac2..63ca82a60 100644 --- a/src/lib/app-provider/hooks/useBaseApiRoute.ts +++ b/src/lib/app-provider/hooks/useBaseApiRoute.ts @@ -1,3 +1,4 @@ +/* eslint-disable complexity */ import { useCelatoneApp } from "../contexts"; import { CELATONE_API_OVERRIDE as api } from "env"; diff --git a/src/lib/components/resource/ResourceDetailCard.tsx b/src/lib/components/resource/ResourceDetailCard.tsx index 4c6cba888..ea6d3bb30 100644 --- a/src/lib/components/resource/ResourceDetailCard.tsx +++ b/src/lib/components/resource/ResourceDetailCard.tsx @@ -91,8 +91,17 @@ export const ResourceDetailCard = ({ > {formattedArray.map((item) => ( - - + + {item.key} {typeof item.value === "object" ? ( diff --git a/src/lib/components/state/EmptyState.tsx b/src/lib/components/state/EmptyState.tsx index 83de71e6b..1c4096281 100644 --- a/src/lib/components/state/EmptyState.tsx +++ b/src/lib/components/state/EmptyState.tsx @@ -27,29 +27,31 @@ export const EmptyState = ({ textVariant = "body1", }: EmptyStateProps) => ( - - {imageVariant && ( - - )} - {heading && ( - - {heading} - - )} - - {message} - - + {imageVariant && ( + + )} + {heading && ( + + {heading} + + )} + + {message} + ); diff --git a/src/lib/components/table/MobileTitle.tsx b/src/lib/components/table/MobileTitle.tsx index 0526769d9..f7c0e6ddc 100644 --- a/src/lib/components/table/MobileTitle.tsx +++ b/src/lib/components/table/MobileTitle.tsx @@ -8,6 +8,7 @@ import { TableTitle } from "./TableTitle"; interface MobileTitleProps { title: string; count: Option; + showCount?: boolean; onViewMore?: () => void; } const cardProps = { @@ -17,14 +18,19 @@ const cardProps = { borderRadius: "8px", }; -export const MobileTitle = ({ onViewMore, title, count }: MobileTitleProps) => ( +export const MobileTitle = ({ + title, + count, + showCount = true, + onViewMore, +}: MobileTitleProps) => ( - + ); diff --git a/src/lib/components/table/TableTitle.tsx b/src/lib/components/table/TableTitle.tsx index de64e5c33..bf9e02715 100644 --- a/src/lib/components/table/TableTitle.tsx +++ b/src/lib/components/table/TableTitle.tsx @@ -1,17 +1,17 @@ import type { BoxProps } from "@chakra-ui/react"; import { Badge, Box, Flex, Heading, Text } from "@chakra-ui/react"; -import type { Option } from "lib/types"; - interface TableTitleProps extends BoxProps { title: string; - count: Option; + count?: number; + showCount?: boolean; helperText?: string; } export const TableTitle = ({ title, count, + showCount = true, helperText, mb = 6, ...props @@ -21,9 +21,11 @@ export const TableTitle = ({ {title} - - {count ?? "N/A"} - + {showCount && ( + + {count ?? "N/A"} + + )} {helperText} diff --git a/src/lib/pages/account-details/components/ErrorFetching.tsx b/src/lib/pages/account-details/components/ErrorFetching.tsx index ce975f05e..ccaf1a3ef 100644 --- a/src/lib/pages/account-details/components/ErrorFetching.tsx +++ b/src/lib/pages/account-details/components/ErrorFetching.tsx @@ -1,8 +1,10 @@ +import { Flex } from "@chakra-ui/react"; + import { CustomIcon } from "lib/components/icon"; export const ErrorFetching = () => ( - <> +

Error fetching data. Please try again later.

- +
); diff --git a/src/lib/pages/account-details/components/modules/ModuleLists.tsx b/src/lib/pages/account-details/components/modules/ModuleLists.tsx index 60f60b511..22fc6a142 100644 --- a/src/lib/pages/account-details/components/modules/ModuleLists.tsx +++ b/src/lib/pages/account-details/components/modules/ModuleLists.tsx @@ -28,7 +28,7 @@ export const ModuleLists = ({ const isMobile = useMobile(); const isMobileOverview = isMobile && !!onViewMore; return ( - + {isMobileOverview ? ( { + const router = useRouter(); + const navigate = useInternalNavigate(); + const [keyword, setKeyword] = useState(""); + + const selectedAccountParam = getFirstQueryParam( + router.query.account, + resourcesByOwner?.[0]?.owner + ); + const selectedNameParam = getFirstQueryParam( + router.query.selected, + resourcesByOwner?.[0]?.resources[0]?.group + ); + + const handleSelectResource = useCallback( + ( + account: ResourceGroupByAccount["owner"], + resource: ResourceGroup["group"] + ) => { + if (account === selectedAccountParam && resource === selectedNameParam) + return; + navigate({ + pathname: `/accounts/[accountAddress]/[tab]`, + query: { + accountAddress: address, + tab: "resources", + account, + selected: resource, + }, + replace: true, + options: { + shallow: true, + }, + }); + }, + [selectedNameParam, selectedAccountParam, address, navigate] + ); + + const filteredResourcesByOwner = useMemo(() => { + if (!keyword) return resourcesByOwner; + + return resourcesByOwner?.map((each) => ({ + ...each, + resources: each.resources.filter((resource) => + resource.group + .toLowerCase() + .includes(keyword.trim().toLocaleLowerCase()) + ), + })); + }, [keyword, resourcesByOwner]); + + const selectedIndex = filteredResourcesByOwner.findIndex( + (item) => item.owner === selectedAccountParam + ); + const selectedGroup = filteredResourcesByOwner[selectedIndex]; + const selectedResources = selectedGroup?.resources.find( + (item) => item.group === selectedNameParam + ); + + return ( + + setKeyword(e.target.value)} + action="execute-message-search" + /> + + {filteredResourcesByOwner.map((item) => ( + + + + + {truncate(item.owner)} + + + + + + {item.resources.length ? ( + + {Object.values(item.resources).map((subitem) => ( + + handleSelectResource(item.owner, subitem.group) + } + hasBorder + /> + ))} + + ) : ( + + No matching resource found + + )} + + + ))} + + + ); +}; diff --git a/src/lib/pages/account-details/components/resources/ResourceOverview.tsx b/src/lib/pages/account-details/components/resources/ResourceOverview.tsx index df631caee..11eb9d18a 100644 --- a/src/lib/pages/account-details/components/resources/ResourceOverview.tsx +++ b/src/lib/pages/account-details/components/resources/ResourceOverview.tsx @@ -36,7 +36,7 @@ export const ResourceOverview = ({ ; resourcesByOwner: Option; isLoading: boolean; } export const ResourceSection = ({ address, + totalCount, resourcesByOwner, isLoading, }: ResourceSectionProps) => ( @@ -20,13 +22,9 @@ export const ResourceSection = ({ - + ; @@ -40,145 +24,87 @@ export const ResourceSectionBody = ({ isLoading, }: ResourceSectionBodyProps) => { const router = useRouter(); - const navigate = useInternalNavigate(); const [expandedIndexes, setExpandedIndexes] = useState([]); - const selectedAccountParam = getFirstQueryParam(router.query.account); - const selectedNameParam = getFirstQueryParam(router.query.selected); - - const handleSelectResource = useCallback( - ( - account: ResourceGroupByAccount["owner"], - resource: ResourceGroup["group"] - ) => { - if (account === selectedAccountParam && resource === selectedNameParam) - return; - navigate({ - pathname: `/accounts/[accountAddress]/[tab]`, - query: { - accountAddress: address, - tab: "resources", - account, - selected: resource, - }, - replace: true, - options: { - shallow: true, - }, - }); - }, - [selectedNameParam, selectedAccountParam, address, navigate] + const selectedAccountParam = getFirstQueryParam( + router.query.account, + resourcesByOwner?.[0]?.owner + ); + const selectedNameParam = getFirstQueryParam( + router.query.selected, + resourcesByOwner?.[0]?.resources[0]?.group ); - const updateExpandedIndexes = (indexes: number[]) => - setExpandedIndexes(indexes); - + const selectedResource = resourcesByOwner + ?.find((resource) => resource.owner === selectedAccountParam) + ?.resources?.find((resource) => resource.group === selectedNameParam); useEffect(() => { - const resourcesLength = resourcesByOwner?.find( - (resource) => resource.owner === selectedAccountParam - )?.resources?.[selectedNameParam].items.length; - - if (resourcesLength === 1) { - setExpandedIndexes([0]); - } else { - setExpandedIndexes([]); - } - }, [resourcesByOwner, selectedNameParam, selectedAccountParam]); + setExpandedIndexes(selectedResource?.items.length === 1 ? [0] : []); + }, [resourcesByOwner, selectedResource]); if (isLoading) return ; if (!resourcesByOwner) return ; if (!resourcesByOwner.length) return ; - const selectedIndex = !selectedAccountParam - ? 0 - : resourcesByOwner.findIndex((item) => item.owner === selectedAccountParam); - const selectedGroup = resourcesByOwner[selectedIndex]; - const selectedGroupArray = Object.values(selectedGroup.resources); - const selectedResources = - selectedGroupArray.find((item) => item.group === selectedNameParam) ?? - selectedGroupArray[0]; return ( <> - - - {resourcesByOwner.map((item) => ( - - - - - {truncate(item.owner)} - - - - - - - {Object.values(item.resources).map((subitem) => ( - - handleSelectResource(item.owner, subitem.group) - } - hasBorder - /> - ))} - - - - ))} - - - - - - - {selectedGroup.owner}::{selectedResources.group} - - - {selectedResources.items.length} - + + {selectedResource && ( + + + + + {selectedResource.account}::{selectedResource.group} + + + {selectedResource.items.length} + + + - - - - {selectedResources.items.map((item) => ( - - ))} - - + {selectedResource.items.map((item) => ( + + ))} + + + )} ); }; diff --git a/src/lib/pages/account-details/index.tsx b/src/lib/pages/account-details/index.tsx index 3cf8054f4..189dff3f6 100644 --- a/src/lib/pages/account-details/index.tsx +++ b/src/lib/pages/account-details/index.tsx @@ -247,7 +247,7 @@ const AccountDetailsBody = ({ {accountInfo?.publicInfo?.description && ( diff --git a/src/lib/pages/module-details/components/ModuleTop.tsx b/src/lib/pages/module-details/components/ModuleTop.tsx index 86eefb436..45e8cef99 100644 --- a/src/lib/pages/module-details/components/ModuleTop.tsx +++ b/src/lib/pages/module-details/components/ModuleTop.tsx @@ -146,7 +146,7 @@ export const ModuleTop = ({ moduleData, isVerified }: ModuleTopProps) => { w={{ base: "full", md: "auto" }} >