134 lines
3.4 KiB
TypeScript
134 lines
3.4 KiB
TypeScript
"use server";
|
|
import { cookies } from "next/headers";
|
|
|
|
import {
|
|
AUTH_COOKIE_NAME,
|
|
BE_BASE_URL,
|
|
REVALIDATE_SECONDS,
|
|
HEALTH_CACHE_TAG,
|
|
} from "./constants";
|
|
import {
|
|
type IDashboardData,
|
|
type IFetchHealthDataParams,
|
|
type IHealthData,
|
|
type IReviewTransactionsData,
|
|
type ITransactionsOverviewData,
|
|
} from "./types";
|
|
|
|
/**
|
|
* Fetch both health and overview data concurrently
|
|
* This is optimized for initial page load
|
|
* Always includes overview data with the provided date range
|
|
*/
|
|
export async function fetchDashboardDataService({
|
|
dateStart,
|
|
dateEnd,
|
|
}: IFetchHealthDataParams): Promise<IDashboardData> {
|
|
const cookieStore = await cookies();
|
|
const token = cookieStore.get(AUTH_COOKIE_NAME)?.value;
|
|
|
|
if (!token) {
|
|
throw new Error("Missing auth token");
|
|
}
|
|
|
|
const queryParts: string[] = [];
|
|
|
|
// Add date filter if provided
|
|
if (dateStart && dateEnd) {
|
|
queryParts.push(
|
|
`Modified=BETWEEN/${encodeURIComponent(dateStart)}/${encodeURIComponent(dateEnd)}`
|
|
);
|
|
} else if (dateStart) {
|
|
queryParts.push(`Modified=>/${encodeURIComponent(dateStart)}`);
|
|
} else if (dateEnd) {
|
|
queryParts.push(`Modified=</${encodeURIComponent(dateEnd)}`);
|
|
}
|
|
|
|
const queryString = queryParts.join("&");
|
|
|
|
const fetchConfig = {
|
|
method: "GET",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
Authorization: `Bearer ${token}`,
|
|
},
|
|
next: {
|
|
revalidate: REVALIDATE_SECONDS,
|
|
tags: [HEALTH_CACHE_TAG],
|
|
},
|
|
};
|
|
|
|
// Fetch all three endpoints concurrently
|
|
const [healthResponse, overviewResponse, reviewResponse] = await Promise.all([
|
|
fetch(
|
|
`${BE_BASE_URL}/api/v1/transactions/health${
|
|
queryString ? `?${queryString}` : ""
|
|
}`,
|
|
fetchConfig
|
|
),
|
|
fetch(
|
|
`${BE_BASE_URL}/api/v1/transactions/overview${
|
|
queryString ? `?${queryString}` : ""
|
|
}`,
|
|
fetchConfig
|
|
),
|
|
fetch(
|
|
`${BE_BASE_URL}/api/v1/transactions?limit=1000${
|
|
queryString ? `&${queryString}` : ""
|
|
}&Status==/review`,
|
|
fetchConfig
|
|
),
|
|
]);
|
|
|
|
// Handle health data response
|
|
if (!healthResponse.ok) {
|
|
const errorData = await healthResponse
|
|
.json()
|
|
.catch(() => ({ message: "Failed to fetch health data" }));
|
|
throw new Error(errorData?.message || "Failed to fetch health data");
|
|
}
|
|
|
|
const healthData = (await healthResponse.json()) as IHealthData;
|
|
|
|
// Handle overview data response
|
|
let overviewData: ITransactionsOverviewData = {
|
|
success: false,
|
|
cancelled: 0,
|
|
failed: 0,
|
|
successful: 0,
|
|
waiting: 0,
|
|
};
|
|
|
|
if (!overviewResponse.ok) {
|
|
// Don't fail the whole request if overview fails, just log it
|
|
console.error("Failed to fetch transactions overview");
|
|
} else {
|
|
overviewData = (await overviewResponse.json()) as ITransactionsOverviewData;
|
|
}
|
|
|
|
// Handle review transactions response
|
|
let reviewTransactions: IReviewTransactionsData = {
|
|
success: false,
|
|
transactions: [],
|
|
total: 0,
|
|
};
|
|
|
|
if (!reviewResponse.ok) {
|
|
// Don't fail the whole request if review transactions fail, just log it
|
|
console.error("Failed to fetch review transactions");
|
|
} else {
|
|
const reviewData = (await reviewResponse.json()) as IReviewTransactionsData;
|
|
reviewTransactions = {
|
|
success: reviewData.success ?? true,
|
|
transactions: reviewData.transactions || [],
|
|
total: reviewData.total || 0,
|
|
};
|
|
}
|
|
|
|
return {
|
|
healthData,
|
|
overviewData,
|
|
reviewTransactions,
|
|
};
|
|
}
|