From de63d93a90d5641ebeacfaa39d10b19bbfd48c4e Mon Sep 17 00:00:00 2001 From: Shreeyash Shrestha Date: Mon, 29 Jun 2026 11:53:00 +0545 Subject: [PATCH] feat(links): add links page module - add globalEnums hooks --- app/Root/index.tsx | 47 ++++++---- app/views/Links/index.tsx | 176 ++++++++++++++++++++++++-------------- app/views/Links/query.ts | 22 +---- 3 files changed, 146 insertions(+), 99 deletions(-) diff --git a/app/Root/index.tsx b/app/Root/index.tsx index d68cc97..8cb8b76 100644 --- a/app/Root/index.tsx +++ b/app/Root/index.tsx @@ -48,7 +48,10 @@ const gqlClient = new Client({ suspense: false, }); -function Root() { +// NOTE: useGlobalEnumsQuery needs UrqlProvider as an parent. +// Since Root itself renders UrqlProvider, the hook must live in +// RootContent a child component mounted inside that provider. +function RootContent() { const [user, setUser] = useState(); const authenticated = !!user; const userContext: UserContextInterface = useMemo(() => ({ @@ -68,26 +71,32 @@ function Root() { dashboardPage: globalEnumsData?.enums.DashboardPage, }), [globalEnumsData]); + return ( + + + + + + {appTitle} + {' '} + loading... + + )} + > + + + + + + ); +} + +function Root() { return ( - - - - - - {appTitle} - {' '} - loading... - - )} - > - - - - - + ); } diff --git a/app/views/Links/index.tsx b/app/views/Links/index.tsx index d9e0e4d..e558074 100644 --- a/app/views/Links/index.tsx +++ b/app/views/Links/index.tsx @@ -1,14 +1,21 @@ import { useCallback, useMemo, + useState, } from 'react'; import { AddFillIcon } from '@ifrc-go/icons'; import { Button, Container, DateInput, + Description, + InlineLayout, + ListView, Pager, + Tab, Table, + TabList, + Tabs, TextInput, } from '@ifrc-go/ui'; import { @@ -19,10 +26,11 @@ import { import EditDeleteActions, { type Props as EditDeleteActionsProps } from '#components/EditDeleteActions'; import { - type InternalLinksQuery, type LinkFilter, + type LinkType, + LinkTypeEnum, useDeleteLinkMutation, - useInternalLinksQuery, + useLinksQuery, } from '#generated/types/graphql'; import useAlert from '#hooks/useAlert'; import useFilterState from '#hooks/useFilterState'; @@ -32,7 +40,7 @@ import { idSelector, } from '#utils/common'; -type InternalLinkListItem = NonNullable['results'][number]> & { no: string } +type LinkListItem = NonNullable & { no: string } interface LinkFilterType extends Omit { createdAtGte: string | undefined; @@ -40,11 +48,13 @@ interface LinkFilterType extends Omit { } const defaultFilter: LinkFilterType = { + linkType: undefined, search: undefined, createdAtGte: undefined, createdAtLte: undefined, }; function Links() { + const [activeTab, setActiveTab] = useState(LinkTypeEnum.Internal); const { filter, rawFilter, @@ -67,6 +77,7 @@ function Links() { offset, }, filters: { + linkType: filter.linkType, search: filter.search, createdAt: (filter.createdAtGte || filter.createdAtLte) ? { gte: filter.createdAtGte, @@ -75,9 +86,18 @@ function Links() { }, }), [limit, offset, filter]); - const [{ fetching, data }, reExecuteQuery] = useInternalLinksQuery( + const [{ fetching, data }, reExecuteQuery] = useLinksQuery( { variables: queryVariables }, ); + + const handleTabChanges = useCallback( + (name: LinkTypeEnum.Internal | LinkTypeEnum.External) => { + setActiveTab(name); + setFilterField(name, 'linkType'); + }, + [setFilterField], + ); + const [, deleteLink] = useDeleteLinkMutation(); const onDeleteClick = useCallback( @@ -98,31 +118,36 @@ function Links() { ); const tableData = useMemo(() => ( - data?.internalLinks.results.map((user, index) => { + data?.publicLinks.results.map((user, index) => { const no = (page - 1) * limit + index + 1; return { ...user, no, }; - }) as unknown as InternalLinkListItem[]), [page, data, limit]); + }) as unknown as LinkListItem[]), [page, data, limit]); const columns = useMemo(() => [ - createStringColumn( + createStringColumn( 'no', 'No.', (item) => item.no, ), - createDateColumn( + createDateColumn( 'createdAt', 'Created At', (item) => item.createdAt, ), - createStringColumn( + createStringColumn( 'title', 'Title', (item) => item.title ?? '-', ), - createElementColumn( + 'linkType', + 'Link Type', + (item) => item.linkTypeDisplay ?? '-', + ), + createElementColumn( 'actions', '', @@ -131,7 +156,7 @@ function Links() { id: datum.id, onDelete: onDeleteClick, itemTitle: datum.title, - to: 'editUser', + to: 'editLink', }), { columnWidth: 150 }, ), @@ -142,59 +167,86 @@ function Links() { }, [navigate]); return ( - - - - + + + Control and manage public-facing resource links + + + + Internal Links + + + External Links + + + )} + /> + + )} + filters={( + <> + + + + + )} + footerActions={( + - - )} - footerActions={( - )} + styleVariant="filled" + > + Create + + )} + > + - )} - headerActions={( - - )} - > -
- + + ); } diff --git a/app/views/Links/query.ts b/app/views/Links/query.ts index f7c7a3d..c2171ac 100644 --- a/app/views/Links/query.ts +++ b/app/views/Links/query.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { gql } from 'urql'; -const EXTERNAL_LINKS = gql` - query ExternalLinks($pagination: OffsetPaginationInput, $filters: LinkFilter) { +const LINKS = gql` + query Links($pagination: OffsetPaginationInput, $filters: LinkFilter) { publicLinks(filters: $filters, pagination: $pagination) { totalCount results { @@ -10,22 +10,8 @@ const EXTERNAL_LINKS = gql` description id title - updatedAt - url - } - } - } -`; - -const INTERNAL_LINKS = gql` - query InternalLinks($pagination: OffsetPaginationInput, $filters: LinkFilter) { - internalLinks(filters: $filters, pagination: $pagination) { - totalCount - results { - createdAt - description - id - title + linkType + linkTypeDisplay updatedAt url }