2025-09-18 14:52:26 +09:00
|
|
|
"use client";
|
2025-09-17 18:43:43 +09:00
|
|
|
|
2025-09-18 17:49:43 +09:00
|
|
|
import {
|
|
|
|
|
useMutation,
|
|
|
|
|
useQuery,
|
|
|
|
|
type UseMutationOptions,
|
|
|
|
|
type UseMutationResult,
|
|
|
|
|
type UseQueryOptions,
|
|
|
|
|
type UseQueryResult,
|
|
|
|
|
} from "@tanstack/react-query";
|
2025-09-20 11:35:40 +09:00
|
|
|
import { apiClient, queryKeys, getDataOrDefault, getDataOrThrow } from "@/lib/api";
|
|
|
|
|
import type { InvoiceQueryParams } from "@/lib/api/types";
|
2025-09-18 17:49:43 +09:00
|
|
|
import type {
|
|
|
|
|
Invoice,
|
|
|
|
|
InvoiceList,
|
|
|
|
|
InvoiceSsoLink,
|
|
|
|
|
PaymentMethodList,
|
2025-09-18 14:52:26 +09:00
|
|
|
} from "@customer-portal/domain";
|
2025-09-25 17:42:36 +09:00
|
|
|
import {
|
|
|
|
|
invoiceListSchema,
|
|
|
|
|
invoiceSchema as sharedInvoiceSchema,
|
|
|
|
|
} from "@customer-portal/domain/validation/shared/entities";
|
2025-09-17 18:43:43 +09:00
|
|
|
|
2025-09-18 17:49:43 +09:00
|
|
|
const emptyInvoiceList: InvoiceList = {
|
|
|
|
|
invoices: [],
|
|
|
|
|
pagination: {
|
|
|
|
|
page: 1,
|
|
|
|
|
totalItems: 0,
|
|
|
|
|
totalPages: 0,
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const emptyPaymentMethods: PaymentMethodList = {
|
|
|
|
|
paymentMethods: [],
|
|
|
|
|
totalCount: 0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
type InvoicesQueryKey = ReturnType<typeof queryKeys.billing.invoices>;
|
|
|
|
|
type InvoiceQueryKey = ReturnType<typeof queryKeys.billing.invoice>;
|
|
|
|
|
type PaymentMethodsQueryKey = ReturnType<typeof queryKeys.billing.paymentMethods>;
|
|
|
|
|
|
|
|
|
|
type InvoicesQueryOptions = Omit<
|
|
|
|
|
UseQueryOptions<InvoiceList, Error, InvoiceList, InvoicesQueryKey>,
|
|
|
|
|
"queryKey" | "queryFn"
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
type InvoiceQueryOptions = Omit<
|
|
|
|
|
UseQueryOptions<Invoice, Error, Invoice, InvoiceQueryKey>,
|
|
|
|
|
"queryKey" | "queryFn"
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
type PaymentMethodsQueryOptions = Omit<
|
|
|
|
|
UseQueryOptions<PaymentMethodList, Error, PaymentMethodList, PaymentMethodsQueryKey>,
|
|
|
|
|
"queryKey" | "queryFn"
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
type SsoLinkMutationOptions = UseMutationOptions<
|
|
|
|
|
InvoiceSsoLink,
|
|
|
|
|
Error,
|
|
|
|
|
{ invoiceId: number; target?: "view" | "download" | "pay" }
|
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
async function fetchInvoices(params?: InvoiceQueryParams): Promise<InvoiceList> {
|
2025-09-26 15:51:07 +09:00
|
|
|
const response = await apiClient.GET<InvoiceList>(
|
2025-09-27 16:59:25 +09:00
|
|
|
"/api/invoices",
|
2025-09-26 15:51:07 +09:00
|
|
|
params ? { params: { query: params as Record<string, unknown> } } : undefined
|
2025-09-25 17:42:36 +09:00
|
|
|
);
|
2025-09-26 15:51:07 +09:00
|
|
|
const data = getDataOrDefault<InvoiceList>(response, emptyInvoiceList);
|
2025-09-25 17:42:36 +09:00
|
|
|
return invoiceListSchema.parse(data);
|
2025-09-18 17:49:43 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function fetchInvoice(id: string): Promise<Invoice> {
|
2025-09-27 16:59:25 +09:00
|
|
|
const response = await apiClient.GET<Invoice>("/api/invoices/{id}", {
|
2025-09-26 15:51:07 +09:00
|
|
|
params: { path: { id } },
|
|
|
|
|
});
|
|
|
|
|
const invoice = getDataOrThrow<Invoice>(response, "Invoice not found");
|
2025-09-25 17:42:36 +09:00
|
|
|
return sharedInvoiceSchema.parse(invoice);
|
2025-09-18 17:49:43 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function fetchPaymentMethods(): Promise<PaymentMethodList> {
|
2025-09-27 16:59:25 +09:00
|
|
|
const response = await apiClient.GET<PaymentMethodList>("/api/invoices/payment-methods");
|
2025-09-26 15:51:07 +09:00
|
|
|
return getDataOrDefault<PaymentMethodList>(response, emptyPaymentMethods);
|
2025-09-18 17:49:43 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useInvoices(
|
|
|
|
|
params?: InvoiceQueryParams,
|
|
|
|
|
options?: InvoicesQueryOptions
|
|
|
|
|
): UseQueryResult<InvoiceList, Error> {
|
2025-09-26 15:51:07 +09:00
|
|
|
const queryParams = params ? (params as Record<string, unknown>) : {};
|
2025-09-18 17:49:43 +09:00
|
|
|
return useQuery({
|
2025-09-26 15:51:07 +09:00
|
|
|
queryKey: queryKeys.billing.invoices(queryParams),
|
2025-09-18 17:49:43 +09:00
|
|
|
queryFn: () => fetchInvoices(params),
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useInvoice(
|
|
|
|
|
id: string,
|
|
|
|
|
options?: InvoiceQueryOptions
|
|
|
|
|
): UseQueryResult<Invoice, Error> {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryKey: queryKeys.billing.invoice(id),
|
|
|
|
|
queryFn: () => fetchInvoice(id),
|
|
|
|
|
enabled: Boolean(id),
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function usePaymentMethods(
|
|
|
|
|
options?: PaymentMethodsQueryOptions
|
|
|
|
|
): UseQueryResult<PaymentMethodList, Error> {
|
|
|
|
|
return useQuery({
|
|
|
|
|
queryKey: queryKeys.billing.paymentMethods(),
|
|
|
|
|
queryFn: fetchPaymentMethods,
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function useCreateInvoiceSsoLink(
|
|
|
|
|
options?: SsoLinkMutationOptions
|
|
|
|
|
): UseMutationResult<
|
|
|
|
|
InvoiceSsoLink,
|
|
|
|
|
Error,
|
|
|
|
|
{ invoiceId: number; target?: "view" | "download" | "pay" }
|
|
|
|
|
> {
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: async ({ invoiceId, target }) => {
|
2025-09-27 16:59:25 +09:00
|
|
|
const response = await apiClient.POST<InvoiceSsoLink>("/api/invoices/{id}/sso-link", {
|
2025-09-18 17:49:43 +09:00
|
|
|
params: {
|
|
|
|
|
path: { id: invoiceId },
|
|
|
|
|
query: target ? { target } : undefined,
|
2025-09-18 14:52:26 +09:00
|
|
|
},
|
2025-09-18 17:49:43 +09:00
|
|
|
});
|
2025-09-25 17:42:36 +09:00
|
|
|
return getDataOrThrow<InvoiceSsoLink>(response, "Failed to create SSO link");
|
2025-09-18 17:49:43 +09:00
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-29 15:26:54 +09:00
|
|
|
|
|
|
|
|
export function useCreatePaymentMethodsSsoLink(
|
|
|
|
|
options?: UseMutationOptions<InvoiceSsoLink, Error, void>
|
|
|
|
|
): UseMutationResult<InvoiceSsoLink, Error, void> {
|
|
|
|
|
return useMutation({
|
|
|
|
|
mutationFn: async () => {
|
|
|
|
|
const response = await apiClient.POST<InvoiceSsoLink>("/auth/sso-link", {
|
|
|
|
|
body: { destination: "index.php?rp=/account/paymentmethods" },
|
|
|
|
|
});
|
|
|
|
|
return getDataOrThrow<InvoiceSsoLink>(response, "Failed to create payment methods SSO link");
|
|
|
|
|
},
|
|
|
|
|
...options,
|
|
|
|
|
});
|
|
|
|
|
}
|