Adding Table Views
ShipAny has a built-in table view component that makes it easy to render a table view for displaying various types of data.
For example, user lists / order lists / point records, etc.
Creating a New Table View
The following steps demonstrate how to quickly render a table view in the user center to display a list of user payment orders.
- First, implement a method in the
model
layer to get the user’s order list from the database
export async function getOrdersByUserUuid(
user_uuid: string
): Promise<Order[] | undefined> {
const now = new Date().toISOString();
const supabase = getSupabaseClient();
const { data, error } = await supabase
.from("orders")
.select("*")
.eq("user_uuid", user_uuid)
.eq("status", "paid")
.order("created_at", { ascending: false });
if (error) {
return undefined;
}
return data;
}
- Create a new page in the user center module to get the logged-in user information
The getUserUuid
method can get the current logged-in user’s uuid from the session.
If the user is not logged in, they will be redirected to the login page.
import { getUserUuid } from "@/services/user";
import { redirect } from "next/navigation";
export default async function MyOrdersPage() {
const user_uuid = await getUserUuid();
const callbackUrl = `${process.env.NEXT_PUBLIC_WEB_URL}/my-orders`;
if (!user_uuid) {
redirect(`/auth/signin?callbackUrl=${encodeURIComponent(callbackUrl)}`);
}
return <div>My Orders With User UUID: {user_uuid}</div>;
}
Preview the new page to see the logged-in user’s uuid.
- Define the table view headers
In the page file:
Define the headers to display columns: TableColumn[]
,
Import the table view component: import TableSlot from "@/components/console/slots/table";
Display the headers: return <TableSlot title={t("my_orders.title")} columns={columns} data={[]} />;
Complete code:
import { TableColumn } from "@/types/blocks/table";
import TableSlot from "@/components/console/slots/table";
import { getTranslations } from "next-intl/server";
import { getUserUuid } from "@/services/user";
import moment from "moment";
import { redirect } from "next/navigation";
export default async function MyOrdersPage() {
const t = await getTranslations();
const user_uuid = await getUserUuid();
const callbackUrl = `${process.env.NEXT_PUBLIC_WEB_URL}/my-orders`;
if (!user_uuid) {
redirect(`/auth/signin?callbackUrl=${encodeURIComponent(callbackUrl)}`);
}
const columns: TableColumn[] = [
{ name: "order_no", title: t("my_orders.table.order_no") },
{ name: "paid_email", title: t("my_orders.table.email") },
{ name: "product_name", title: t("my_orders.table.product_name") },
{
name: "amount",
title: t("my_orders.table.amount"),
callback: (item: any) =>
`${item.currency.toUpperCase() === "CNY" ? "¥" : "$"} ${
item.amount / 100
}`,
},
{
name: "paid_at",
title: t("my_orders.table.paid_at"),
callback: (item: any) =>
moment(item.paid_at).format("YYYY-MM-DD HH:mm:ss"),
},
];
return <TableSlot title={t("my_orders.title")} columns={columns} data={[]} />;
}
Preview effect:
- Display data in the table view
Call the data reading function implemented in step 1 and pass the retrieved data to the table view component for display.
Complete code:
import { getOrdersByPaidEmail, getOrdersByUserUuid } from "@/models/order";
import { getUserEmail, getUserUuid } from "@/services/user";
import { TableColumn } from "@/types/blocks/table";
import TableSlot from "@/components/console/slots/table";
import { Table as TableSlotType } from "@/types/slots/table";
import { getTranslations } from "next-intl/server";
import moment from "moment";
import { redirect } from "next/navigation";
export default async function () {
const t = await getTranslations();
const user_uuid = await getUserUuid();
const user_email = await getUserEmail();
const callbackUrl = `${process.env.NEXT_PUBLIC_WEB_URL}/my-orders`;
if (!user_uuid) {
redirect(`/auth/signin?callbackUrl=${encodeURIComponent(callbackUrl)}`);
}
let orders = await getOrdersByUserUuid(user_uuid);
if (!orders || orders.length === 0) {
orders = await getOrdersByPaidEmail(user_email);
}
const columns: TableColumn[] = [
{ name: "order_no", title: t("my_orders.table.order_no") },
{ name: "paid_email", title: t("my_orders.table.email") },
{ name: "product_name", title: t("my_orders.table.product_name") },
{
name: "amount",
title: t("my_orders.table.amount"),
callback: (item: any) =>
`${item.currency.toUpperCase() === "CNY" ? "¥" : "$"} ${
item.amount / 100
}`,
},
{
name: "paid_at",
title: t("my_orders.table.paid_at"),
callback: (item: any) =>
moment(item.paid_at).format("YYYY-MM-DD HH:mm:ss"),
},
];
const table: TableSlotType = {
title: t("my_orders.title"),
description: t("my_orders.description"),
toolbar: {
items: [
{
title: t("my_orders.read_docs"),
icon: "RiBookLine",
url: "https://docs.shipany.ai",
target: "_blank",
variant: "outline",
},
{
title: t("my_orders.join_discord"),
icon: "RiDiscordFill",
url: "https://discord.gg/HQNnrzjZQS",
target: "_blank",
},
],
},
columns: columns,
data: orders,
empty_message: t("my_orders.no_orders"),
};
return <TableSlot {...table} />;
}
Preview effect: