Improve look and performance of orders table

This commit is contained in:
Dominic Ferrando
2026-07-17 15:33:17 -04:00
parent 1673bc5498
commit fdbfbb125d
3 changed files with 147 additions and 67 deletions
+26
View File
@@ -237,6 +237,32 @@ export const app = new Elysia()
}) })
) )
.group("/orders", (app) => app .group("/orders", (app) => app
.get("/", async ({ query }) => {
const wOrders = await s.Commerce.Webflow.Orders.list({
status: query.status,
limit: query.limit,
offset: query.offset,
});
const isSyncedFlags = await Promise.all(
wOrders.map(async (wOrder) =>
(await s.Commerce.Printful.Orders.get(`@${wOrder.orderId}`)) !== undefined
)
);
return wOrders.map((wOrder, i) => ({ wOrder, isSynced: isSyncedFlags[i] }));
}, {
query: t.Object({
status: t.Optional(t.Union([
t.Literal("pending"),
t.Literal("unfulfilled"),
t.Literal("fulfilled"),
t.Literal("disputed"),
t.Literal("dispute-lost"),
t.Literal("refunded"),
])),
limit: t.Optional(t.Numeric()),
offset: t.Optional(t.Numeric()),
})
})
.get("/:wOrderId", async ({ params: { wOrderId } }) => { .get("/:wOrderId", async ({ params: { wOrderId } }) => {
const wOrder = await s.Commerce.Webflow.Orders.get(wOrderId); const wOrder = await s.Commerce.Webflow.Orders.get(wOrderId);
if (!wOrder) throw new NotFoundError("Missing webflow order"); if (!wOrder) throw new NotFoundError("Missing webflow order");
@@ -1,12 +0,0 @@
import { printful } from "$lib/printful";
import { webflow } from "$lib/webflow";
import type { PageServerLoad } from "./$types";
export const load = async ({ }: Parameters<PageServerLoad>[0]) => {
return {
orders: {
printful: printful.Orders.list({ forceAll: true }),
webflow: webflow.Orders.list({ forceAll: true }),
},
};
};
@@ -1,62 +1,128 @@
<script lang="ts"> <script lang="ts">
import { api } from "$lib/api.js"; import { api } from "$lib/api.js";
import type { Webflow } from "@blade-and-brawn/commerce"; import { onMount } from "svelte";
const { data } = $props(); type OrderRow = NonNullable<
Awaited<ReturnType<typeof api.commerce.orders.get>>["data"]
>[number];
const isOrderSynced = async (wOrder: Webflow.Orders.Order) => { const LIMIT = 25;
const pOrders = await data.orders.printful;
return pOrders.some((pOrder) => pOrder.external_id === wOrder.orderId); let orders = $state<OrderRow[]>([]);
}; let loading = $state(true);
let loadError = $state<string | null>(null);
let offset = $state(0);
function errorMessage(err: unknown): string {
const value = (err as { value?: { error?: string } })?.value;
return (
value?.error ??
(err instanceof Error ? err.message : "Unknown error")
);
}
async function refresh() {
loading = true;
loadError = null;
try {
const res = await api.commerce.orders.get({
query: {
limit: LIMIT,
offset,
},
});
if (res.error) throw res.error;
orders = res.data as OrderRow[];
} catch (err) {
loadError = errorMessage(err);
} finally {
loading = false;
}
}
function prevPage() {
offset = Math.max(0, offset - LIMIT);
refresh();
}
function nextPage() {
offset += LIMIT;
refresh();
}
onMount(refresh);
</script> </script>
{#await data.orders.webflow} <div class="w-full flex items-center gap-2 flex-wrap mt-10 mb-5">
<p>Loading...</p> <button class="btn btn-sm" onclick={refresh} disabled={loading}>
{:then wOrders} {loading ? "Refreshing..." : "Refresh"}
<div class="w-full mt-10 overflow-x-auto"> </button>
<table class="table">
<thead> <div class="flex-1"></div>
<tr>
<th>Id</th> <button
<th>Status</th> class="btn btn-sm"
</tr> onclick={prevPage}
</thead> disabled={offset === 0 || loading}
<tbody> >
{#each wOrders as wOrder} Prev
<tr class="hover:bg-base-300"> </button>
<td <button
><button class="btn btn-sm"
onclick={async () => { onclick={nextPage}
const res = await api.commerce disabled={orders.length < LIMIT || loading}
.orders({ >
wOrderId: wOrder.orderId, Next
}) </button>
.get(); </div>
console.log(res.data);
}} {#if loadError}
class="cursor-pointer underline" <div role="alert" class="alert alert-error w-full mb-4">
> <span>{loadError}</span>
{wOrder.orderId}
</button></td
>
<td>
{#await isOrderSynced(wOrder) then isSynced}
{#if isSynced}
<div class="badge badge-success">
Synced
</div>
{:else}
<div class="badge badge-error">
Desynced
</div>
{/if}
{/await}
</td>
</tr>
{/each}
</tbody>
</table>
</div> </div>
{:catch error} {/if}
<p>Something went wrong: {error.message}</p>
{/await} <div class="w-full overflow-x-auto">
<table class="table">
<thead>
<tr>
<th>Id</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{#each orders as order (order.wOrder.orderId)}
<tr class="hover:bg-base-300">
<td
><button
onclick={async () => {
const res = await api.commerce
.orders({
wOrderId: order.wOrder.orderId,
})
.get();
console.log(res.data);
}}
class="cursor-pointer underline"
>
{order.wOrder.orderId}
</button></td
>
<td>
{#if order.isSynced}
<div class="badge badge-success">Synced</div>
{:else}
<div class="badge badge-error">Desynced</div>
{/if}
</td>
</tr>
{:else}
<tr>
<td colspan="2" class="text-center opacity-60">
{loading ? "Loading..." : "No orders found"}
</td>
</tr>
{/each}
</tbody>
</table>
</div>