Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions app/Root/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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<MeQuery['me'] | undefined>();
const authenticated = !!user;
const userContext: UserContextInterface = useMemo(() => ({
Expand All @@ -68,26 +71,32 @@ function Root() {
dashboardPage: globalEnumsData?.enums.DashboardPage,
}), [globalEnumsData]);

return (
<UserContext.Provider value={userContext}>
<GlobalEnumsContext.Provider value={globalEnumsContext}>
<AlertContext.Provider value={alertContextValue}>
<AlertContainer />
<Suspense
fallback={(
<PreloadMessage>
{appTitle}
{' '}
loading...
</PreloadMessage>
)}
>
<Outlet />
</Suspense>
</AlertContext.Provider>
</GlobalEnumsContext.Provider>
</UserContext.Provider>
);
}

function Root() {
return (
<UrqlProvider value={gqlClient}>
<UserContext.Provider value={userContext}>
<GlobalEnumsContext.Provider value={globalEnumsContext}>
<AlertContext.Provider value={alertContextValue}>
<AlertContainer />
<Suspense
fallback={(
<PreloadMessage>
{appTitle}
{' '}
loading...
</PreloadMessage>
)}
>
<Outlet />
</Suspense>
</AlertContext.Provider>
</GlobalEnumsContext.Provider>
</UserContext.Provider>
<RootContent />
</UrqlProvider>
);
}
Expand Down
176 changes: 114 additions & 62 deletions app/views/Links/index.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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';
Expand All @@ -32,19 +40,21 @@ import {
idSelector,
} from '#utils/common';

type InternalLinkListItem = NonNullable<NonNullable<InternalLinksQuery['internalLinks']>['results'][number]> & { no: string }
type LinkListItem = NonNullable<LinkType> & { no: string }

interface LinkFilterType extends Omit<LinkFilter, 'createdAt'> {
createdAtGte: string | undefined;
createdAtLte: string | undefined;
}

const defaultFilter: LinkFilterType = {
linkType: undefined,
search: undefined,
createdAtGte: undefined,
createdAtLte: undefined,
};
function Links() {
const [activeTab, setActiveTab] = useState<LinkTypeEnum>(LinkTypeEnum.Internal);
const {
filter,
rawFilter,
Expand All @@ -67,6 +77,7 @@ function Links() {
offset,
},
filters: {
linkType: filter.linkType,
search: filter.search,
createdAt: (filter.createdAtGte || filter.createdAtLte) ? {
gte: filter.createdAtGte,
Expand All @@ -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(
Expand All @@ -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<InternalLinkListItem, string | number>(
createStringColumn<LinkListItem, string | number>(
'no',
'No.',
(item) => item.no,
),
createDateColumn<InternalLinkListItem, string | number>(
createDateColumn<LinkListItem, string | number>(
'createdAt',
'Created At',
(item) => item.createdAt,
),
createStringColumn<InternalLinkListItem, string | number>(
createStringColumn<LinkListItem, string | number>(
'title',
'Title',
(item) => item.title ?? '-',
),
createElementColumn<InternalLinkListItem, string | number,
createStringColumn<LinkListItem, string | number>(
'linkType',
'Link Type',
(item) => item.linkTypeDisplay ?? '-',
),
createElementColumn<LinkListItem, string | number,
EditDeleteActionsProps>(
'actions',
'',
Expand All @@ -131,7 +156,7 @@ function Links() {
id: datum.id,
onDelete: onDeleteClick,
itemTitle: datum.title,
to: 'editUser',
to: 'editLink',
}),
{ columnWidth: 150 },
),
Expand All @@ -142,59 +167,86 @@ function Links() {
}, [navigate]);

return (
<Container
withPadding
heading="Links"
headerDescription="Control and manage public-facing resource links"
filters={(
<>
<DateInput
name="createdAtGte"
label="Created at start date"
value={rawFilter.createdAtGte}
onChange={setFilterField}
/>
<DateInput
name="createdAtLte"
label="Created at end date"
value={rawFilter.createdAtLte}
onChange={setFilterField}
/>
<TextInput
name="search"
placeholder="Search"
value={rawFilter.search}
onChange={setFilterField}
<Tabs
onChange={handleTabChanges}
value={activeTab}
>
<Container
withPadding
heading="Links"
headerDescription={(
<ListView layout="block">
<Description>
Control and manage public-facing resource links
</Description>
<InlineLayout
before={(
<TabList>
<Tab
name={LinkTypeEnum.Internal}
>
Internal Links
</Tab>
<Tab
name={LinkTypeEnum.External}
>
External Links
</Tab>
</TabList>
)}
/>
</ListView>
)}
filters={(
<>
<DateInput
name="createdAtGte"
label="Created at start date"
value={rawFilter.createdAtGte}
onChange={setFilterField}
/>
<DateInput
name="createdAtLte"
label="Created at end date"
value={rawFilter.createdAtLte}
onChange={setFilterField}
/>
<TextInput
name="search"
placeholder="Search"
value={rawFilter.search}
onChange={setFilterField}
/>
</>
)}
footerActions={(
<Pager
activePage={page}
itemsCount={data?.publicLinks.totalCount ?? 0}
maxItemsPerPage={limit}
onActivePageChange={setPage}
/>
</>
)}
footerActions={(
<Pager
activePage={page}
itemsCount={data?.internalLinks.totalCount ?? 0}
maxItemsPerPage={limit}
onActivePageChange={setPage}
)}
headerActions={(
<Button
name={undefined}
onClick={handleCreateClick}
before={(<AddFillIcon />)}
styleVariant="filled"
>
Create
</Button>
)}
>
<Table
keySelector={idSelector}
columns={columns}
data={tableData}
filtered={filtered}
pending={fetching}
/>
)}
headerActions={(
<Button
name={undefined}
onClick={handleCreateClick}
before={(<AddFillIcon />)}
styleVariant="filled"
>
Create
</Button>
)}
>
<Table
keySelector={idSelector}
columns={columns}
data={tableData}
filtered={filtered}
pending={fetching}
/>
</Container>
</Container>
</Tabs>
);
}

Expand Down
22 changes: 4 additions & 18 deletions app/views/Links/query.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
/* 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 {
createdAt
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
}
Expand Down
Loading