Skip to content

Commit

Permalink
feat(admin_ui): add filter, loader and sorting to the tables (#643)
Browse files Browse the repository at this point in the history
* chore: update apsara version

* refactor: remove loading check from column definitions

* refactor: remove loading check from roles and user table

* refactor: remove loading check from billing list

* refactor: remove loading check from groups list

* refactor: remove loading check from projects list

* refactor: remove loading check from users list

* refactor: remove loading check from products list

* refactor: remove loading check from preferences list

* refactor: remove loading check and add filter in invoices list
  • Loading branch information
rsbh authored Jun 13, 2024
1 parent 6d7907e commit e2b16d2
Show file tree
Hide file tree
Showing 24 changed files with 289 additions and 413 deletions.
9 changes: 5 additions & 4 deletions ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@radix-ui/colors": "^0.1.8",
"@radix-ui/react-form": "^0.0.2",
"@radix-ui/react-icons": "^1.3.0",
"@raystack/apsara": "^0.12.0",
"@raystack/apsara": "^0.14.1",
"@raystack/frontier": "^0.14.0",
"@stitches/react": "^1.2.8",
"@tanstack/react-table": "^8.9.3",
Expand Down
50 changes: 17 additions & 33 deletions ui/src/containers/billingplans.list/columns.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,28 @@
import { ApsaraColumnDef } from "@raystack/apsara";
import { V1Beta1Plan } from "@raystack/frontier";
import type { ColumnDef } from "@tanstack/react-table";
import { createColumnHelper } from "@tanstack/react-table";
import Skeleton from "react-loading-skeleton";
import { Link } from "react-router-dom";

const columnHelper = createColumnHelper<V1Beta1Plan>();

interface getColumnsOptions {
isLoading: boolean;
}

export const getColumns: (
options: getColumnsOptions
) => ColumnDef<V1Beta1Plan, any>[] = ({ isLoading }) => {
export const getColumns: () => ApsaraColumnDef<V1Beta1Plan>[] = () => {
return [
columnHelper.accessor("id", {
{
header: "ID",
//@ts-ignore
accessorKey: "id",
filterVariant: "text",
cell: isLoading
? () => <Skeleton />
: ({ row, getValue }) => {
return (
<Link to={`/plans/${row.getValue("id")}`}>{getValue()}</Link>
);
},
}),
cell: ({ row, getValue }) => (
<Link to={`/plans/${row.getValue("id")}`}>{getValue()}</Link>
),
},
{
header: "Title",
accessorKey: "title",
filterVariant: "text",
cell: isLoading ? () => <Skeleton /> : (info) => info.getValue(),
cell: (info) => info.getValue(),
},
{
header: "Interval",
accessorKey: "interval",
filterVariant: "text",
cell: isLoading ? () => <Skeleton /> : (info) => info.getValue(),
cell: (info) => info.getValue(),
footer: (props) => props.column.id,
},
{
Expand All @@ -45,15 +31,13 @@ export const getColumns: (
meta: {
headerFilter: false,
},
cell: isLoading
? () => <Skeleton />
: (info) =>
new Date(info.getValue() as Date).toLocaleString("en", {
month: "long",
day: "numeric",
year: "numeric",
}),

cell: (info) =>
new Date(info.getValue() as Date).toLocaleString("en", {
month: "long",
day: "numeric",
year: "numeric",
}),
filterVariant: "date",
footer: (props) => props.column.id,
},
];
Expand Down
5 changes: 2 additions & 3 deletions ui/src/containers/billingplans.list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ export default function PlanList() {
}))
: plans;

const columns = getColumns({
isLoading: isPlansLoading,
});
const columns = getColumns();

return (
<Flex direction="row" style={{ height: "100%", width: "100%" }}>
Expand All @@ -65,6 +63,7 @@ export default function PlanList() {
emptyState={noDataChildren}
parentStyle={{ height: "calc(100vh - 60px)" }}
style={tableStyle}
isLoading={isPlansLoading}
>
<DataTable.Toolbar>
<PlanHeader header={pageHeader} />
Expand Down
60 changes: 23 additions & 37 deletions ui/src/containers/groups.list/columns.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,59 @@
import { V1Beta1Group, V1Beta1Organization } from "@raystack/frontier";
import type { ColumnDef } from "@tanstack/react-table";
import { createColumnHelper } from "@tanstack/react-table";
import Skeleton from "react-loading-skeleton";
import { Link } from "react-router-dom";
import * as R from "ramda";
import { Text } from "@raystack/apsara";
const columnHelper = createColumnHelper<V1Beta1Group>();
import { ApsaraColumnDef, Text } from "@raystack/apsara";

interface getColumnsOptions {
isLoading: boolean;
orgMap: Record<string, V1Beta1Organization>;
}

export const getColumns: (
opt: getColumnsOptions
) => ColumnDef<V1Beta1Group, any>[] = ({ orgMap, isLoading }) => {
) => ApsaraColumnDef<V1Beta1Group>[] = ({ orgMap }) => {
return [
columnHelper.accessor("id", {
header: "ID",
//@ts-ignore
{
header: "Id",
accessorKey: "id",
filterVariant: "text",
cell: isLoading
? () => <Skeleton />
: ({ row, getValue }) => {
return <Link to={`${row.getValue("id")}`}>{getValue()}</Link>;
},
}),
cell: ({ row, getValue }) => {
return <Link to={`${row.getValue("id")}`}>{getValue()}</Link>;
},
},
{
header: "Title",
accessorKey: "title",
cell: isLoading ? () => <Skeleton /> : (info: any) => info.getValue(),
cell: (info: any) => info.getValue(),
filterVariant: "text",
},
{
header: "Organization",
accessorKey: "org_id",
cell: isLoading
? () => <Skeleton />
: (info) => {
const orgId = info.getValue();
const orgName = R.pathOr(orgId, [orgId, "title"], orgMap);
return <Text>{orgName}</Text>;
},
cell: (info) => {
const orgId = info.getValue();
const orgName = R.pathOr(orgId, [orgId, "title"], orgMap);
return <Text>{orgName}</Text>;
},
meta: {
data: Object.entries(orgMap).map(([k, v]) => ({
label: v?.title,
value: k,
})),
},
filterFn: (row, id, value) => {
return value.includes(row.getValue(id));
},
filterVariant: "select",
},
{
header: "Created At",
accessorKey: "created_at",
filterVariant: "text",
filterVariant: "date",
meta: {
headerFilter: false,
},
cell: isLoading
? () => <Skeleton />
: (info: any) =>
new Date(info.getValue() as Date).toLocaleString("en", {
month: "long",
day: "numeric",
year: "numeric",
}),

cell: (info: any) =>
new Date(info.getValue() as Date).toLocaleString("en", {
month: "long",
day: "numeric",
year: "numeric",
}),
footer: (props: any) => props.column.id,
},
];
Expand Down
2 changes: 1 addition & 1 deletion ui/src/containers/groups.list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ export default function GroupList() {
: groups;

const columns = getColumns({
isLoading: isGroupsLoading,
orgMap,
});

Expand All @@ -61,6 +60,7 @@ export default function GroupList() {
emptyState={noDataChildren}
parentStyle={{ height: "calc(100vh - 60px)" }}
style={tableStyle}
isLoading={isGroupsLoading}
>
<DataTable.Toolbar>
<GroupsHeader />
Expand Down
98 changes: 41 additions & 57 deletions ui/src/containers/invoices.list/columns.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { V1Beta1Invoice, V1Beta1Organization } from "@raystack/frontier";
import { ColumnDef } from "@tanstack/react-table";
import Skeleton from "react-loading-skeleton";
import { Link } from "react-router-dom";
import { Text } from "@raystack/apsara";
import { ApsaraColumnDef, Text } from "@raystack/apsara";
import dayjs from "dayjs";
import * as R from "ramda";
import { DEFAULT_DATE_FORMAT } from "~/utils/constants";

interface getColumnsOptions {
isLoading: boolean;
billingOrgMap: Record<string, string>;
orgMap: Record<string, V1Beta1Organization>;
}
Expand All @@ -16,82 +14,68 @@ const currencyDecimal = 2;

export const getColumns: (
opt: getColumnsOptions
) => ColumnDef<V1Beta1Invoice, any>[] = ({
orgMap,
isLoading,
billingOrgMap,
}) => {
) => ApsaraColumnDef<V1Beta1Invoice>[] = ({ orgMap, billingOrgMap }) => {
return [
{
header: "Date",
filterVariant: "date",
accessorKey: "due_date",
cell: isLoading
? () => <Skeleton />
: ({ row, getValue }) => {
const date = getValue() || row.original.period_end_at;
return <Text>{dayjs(date).format("MMM DD, YYYY")}</Text>;
},
cell: ({ row, getValue }) => {
const date = getValue() || row.original.period_end_at;
return <Text>{dayjs(date).format(DEFAULT_DATE_FORMAT)}</Text>;
},
},
{
header: "Amount",
accessorKey: "amount",
cell: isLoading
? () => <Skeleton />
: ({ row, getValue }) => {
const currency = row?.original?.currency;
cell: ({ row, getValue }) => {
const currency = row?.original?.currency;

const value = getValue();
const value = getValue();

const calculatedValue = (
value / Math.pow(10, currencyDecimal)
).toFixed(currencyDecimal);
const [intValue, decimalValue] = calculatedValue
.toString()
.split(".");
const calculatedValue = (value / Math.pow(10, currencyDecimal)).toFixed(
currencyDecimal
);
const [intValue, decimalValue] = calculatedValue.toString().split(".");

return (
<Text>
{currency} {intValue}.{decimalValue}
</Text>
);
},
return (
<Text>
{currency} {intValue}.{decimalValue}
</Text>
);
},
},
{
header: "Organization",
accessorKey: "customer_id",
cell: isLoading
? () => <Skeleton />
: ({ row, getValue }) => {
const billingId = getValue();
const orgId = R.pathOr("", [billingId], billingOrgMap);
const orgName = R.pathOr("", [orgId, "title"], orgMap);
return <Text>{orgName}</Text>;
},
cell: ({ row, getValue }) => {
const billingId = getValue();
const orgId = R.pathOr("", [billingId], billingOrgMap);
const orgName = R.pathOr("", [orgId, "title"], orgMap);
return <Text>{orgName}</Text>;
},
},
{
header: "State",
accessorKey: "state",
cell: isLoading
? () => <Skeleton />
: ({ row, getValue }) => {
return <Text>{getValue()}</Text>;
},
cell: ({ row, getValue }) => {
return <Text>{getValue()}</Text>;
},
},
{
header: "Link",
accessorKey: "hosted_url",
cell: isLoading
? () => <Skeleton />
: ({ row, getValue }) => {
const link = getValue();
return link ? (
<Link to={link} target="__blank">
Link
</Link>
) : (
<Text>-</Text>
);
},
enableColumnFilter: false,
cell: ({ row, getValue }) => {
const link = getValue();
return link ? (
<Link to={link} target="__blank">
Link
</Link>
) : (
<Text>-</Text>
);
},
},
];
};
15 changes: 15 additions & 0 deletions ui/src/containers/invoices.list/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { DataTable, useTable } from "@raystack/apsara";
import PageHeader from "~/components/page-header";

export const InvoicesHeader = ({ header }: any) => {
const { filteredColumns } = useTable();
const isFiltered = filteredColumns.length > 0;

return (
<PageHeader title={header.title} breadcrumb={header?.breadcrumb || []}>
{isFiltered ? <DataTable.ClearFilter /> : <DataTable.FilterOptions />}
<DataTable.ViewOptions />
<DataTable.GloabalSearch placeholder="Search invoices..." />
</PageHeader>
);
};
Loading

0 comments on commit e2b16d2

Please sign in to comment.