nxtgauge-frontend-solid/src/routes/dashboard/wallet/invoices/index.tsx
Tracewebstudio Dev 4efe848f3a
All checks were successful
build-and-release / build (push) Successful in 2m15s
fix: local dev proxy, TypeScript errors, and test quality
- middleware.ts: default GATEWAY_URL to localhost:9100 (was K8s hostname);
  proxy all /api/* to gateway instead of falling through to SolidStart renderer
- signup/index.tsx: fix kebab-case style property (align-items)
- dashboard/CreditsPage.tsx: fix IIFE closing in Show children
- AskAsh/index.ts: use ~ alias to fix bundler module resolution
- vite.config.ts: add string type to rewrite callback
- global.d.ts: add Window.__captchaCode and __testMode declarations
- help-center/article/[slug].tsx: add missing ContentBlock import
- test/setup.ts: add vitest/globals reference, fix IntersectionObserver mock
- tests/e2e: fix implicit any, string|null/undefined type errors in e2e specs
- tests/tsconfig.json: add tests-specific tsconfig with node types

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-17 00:47:32 +02:00

134 lines
4.8 KiB
TypeScript

import { createResource, Show, For } from "solid-js";
import { A } from "@solidjs/router";
import DashboardLayout from "~/components/DashboardLayout";
import { api } from "~/lib/api";
interface InvoiceSummary {
id: string;
invoice_number: string;
payment_id: string;
status: string;
currency: string;
subtotal: number;
cgst_amount: number;
sgst_amount: number;
igst_amount: number;
total: number;
issued_at: string;
paid_at: string | null;
pdf_object_key: string | null;
package_name: string | null;
}
interface InvoicesResponse {
invoices: InvoiceSummary[];
page: number;
limit: number;
}
export default function InvoicesPage() {
const [data] = createResource(async () => {
const res = await api.get<InvoicesResponse>("/wallet/me/invoices");
return res.data;
});
const formatDate = (date: string) => {
return new Date(date).toLocaleDateString("en-IN", {
day: "numeric",
month: "short",
year: "numeric",
});
};
const formatPrice = (paise: number) => {
return new Intl.NumberFormat("en-IN", {
style: "currency",
currency: "INR",
minimumFractionDigits: 0,
}).format(paise / 100);
};
return (
<DashboardLayout>
<div class="p-6 max-w-5xl mx-auto">
<h1 class="text-2xl font-bold mb-2">Invoices</h1>
<p class="text-gray-600 mb-6">All your Tracecoin purchase invoices</p>
<Show when={data.loading}>
<div class="text-center py-12">
<div class="animate-spin w-8 h-8 border-2 border-orange-500 border-t-transparent rounded-full mx-auto mb-4" />
<p class="text-gray-500">Loading invoices...</p>
</div>
</Show>
<Show when={data()} keyed>
{(d) => (
<Show
when={d.invoices.length > 0}
fallback={
<div class="bg-white border rounded-xl p-12 text-center">
<p class="text-gray-500 text-lg">No invoices yet.</p>
<p class="text-gray-400 text-sm mt-2">
Invoices are generated automatically when you purchase a Tracecoin package.
</p>
</div>
}
>
<div class="bg-white border rounded-xl overflow-hidden">
<table class="w-full text-sm">
<thead>
<tr class="text-left text-xs uppercase text-gray-500 border-b bg-gray-50">
<th class="px-4 py-3">Invoice #</th>
<th class="px-4 py-3">Package</th>
<th class="px-4 py-3">Date</th>
<th class="px-4 py-3 text-right">Total</th>
<th class="px-4 py-3">Status</th>
<th class="px-4 py-3"></th>
</tr>
</thead>
<tbody>
<For each={d.invoices}>
{(inv) => (
<tr class="border-b hover:bg-gray-50">
<td class="px-4 py-3 font-mono text-sm">{inv.invoice_number}</td>
<td class="px-4 py-3">{inv.package_name ?? "Tracecoin purchase"}</td>
<td class="px-4 py-3 text-gray-600">{formatDate(inv.issued_at)}</td>
<td class="px-4 py-3 text-right font-medium">
{formatPrice(inv.total)}
</td>
<td class="px-4 py-3">
<span
class={`inline-block px-2 py-1 rounded-full text-xs font-medium ${
inv.status === "PAID"
? "bg-green-100 text-green-700"
: inv.status === "ISSUED"
? "bg-blue-100 text-blue-700"
: inv.status === "VOID"
? "bg-red-100 text-red-700"
: "bg-gray-100 text-gray-700"
}`}
>
{inv.status}
</span>
</td>
<td class="px-4 py-3 text-right">
<A
href={`/dashboard/wallet/invoices/${inv.id}`}
class="text-orange-600 hover:underline text-sm"
>
View
</A>
</td>
</tr>
)}
</For>
</tbody>
</table>
</div>
</Show>
)}
</Show>
</div>
</DashboardLayout>
);
}