mirror of
				https://github.com/i701/sarlink-portal.git
				synced 2025-11-04 00:16:59 +00:00 
			
		
		
		
	
		
			All checks were successful
		
		
	
	Build and Push Docker Images / Build and Push Docker Images (push) Successful in 6m16s
				
			
		
			
				
	
	
		
			384 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			384 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
"use server";
 | 
						|
 | 
						|
import { revalidatePath } from "next/cache";
 | 
						|
import { getServerSession } from "next-auth";
 | 
						|
import { authOptions } from "@/app/auth";
 | 
						|
import type {
 | 
						|
	ApiError,
 | 
						|
	ApiResponse,
 | 
						|
	NewPayment,
 | 
						|
	Payment,
 | 
						|
	Topup,
 | 
						|
} from "@/lib/backend-types";
 | 
						|
import type { TopupResponse } from "@/lib/types";
 | 
						|
import { handleApiResponse } from "@/utils/tryCatch";
 | 
						|
 | 
						|
type GenericGetResponseProps = {
 | 
						|
	offset?: number;
 | 
						|
	limit?: number;
 | 
						|
	page?: number;
 | 
						|
	[key: string]: string | number | undefined;
 | 
						|
};
 | 
						|
 | 
						|
export async function createPayment(data: NewPayment) {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	console.log("data", data);
 | 
						|
	const response = await fetch(
 | 
						|
		`${
 | 
						|
			process.env.SARLINK_API_BASE_URL // });
 | 
						|
		}/api/billing/payment/`,
 | 
						|
		{
 | 
						|
			method: "POST",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
			body: JSON.stringify(data),
 | 
						|
		},
 | 
						|
	);
 | 
						|
	if (!response.ok) {
 | 
						|
		const errorData = (await response.json()) as ApiError;
 | 
						|
		const errorMessage =
 | 
						|
			errorData.message || errorData.detail || "An error occurred.";
 | 
						|
		const error = new Error(errorMessage);
 | 
						|
		(error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object
 | 
						|
		throw error;
 | 
						|
	}
 | 
						|
	const payment = (await response.json()) as Payment;
 | 
						|
	revalidatePath("/devices");
 | 
						|
	return payment;
 | 
						|
}
 | 
						|
 | 
						|
export async function createTopup(data: { amount: number }) {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/topup/`,
 | 
						|
		{
 | 
						|
			method: "POST",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
			body: JSON.stringify(data),
 | 
						|
		},
 | 
						|
	);
 | 
						|
	return handleApiResponse<Topup>(response, "createTopup");
 | 
						|
}
 | 
						|
 | 
						|
export async function getPayment({ id }: { id: string }) {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${id}`,
 | 
						|
		{
 | 
						|
			method: "GET",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	);
 | 
						|
 | 
						|
	if (!response.ok) {
 | 
						|
		const errorData = (await response.json()) as ApiError;
 | 
						|
		const errorMessage =
 | 
						|
			errorData.message || errorData.detail || "An error occurred.";
 | 
						|
		const error = new Error(errorMessage);
 | 
						|
		(error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object
 | 
						|
		throw error;
 | 
						|
	}
 | 
						|
	const data = (await response.json()) as Payment;
 | 
						|
	return data;
 | 
						|
}
 | 
						|
 | 
						|
type GetPaymentProps = {
 | 
						|
	[key: string]: string | number | undefined; // Allow additional properties for flexibility
 | 
						|
};
 | 
						|
 | 
						|
export async function getPayments(
 | 
						|
	params: GetPaymentProps,
 | 
						|
	allPayments = false,
 | 
						|
) {
 | 
						|
	// Build query string from all defined params
 | 
						|
	const query = Object.entries(params)
 | 
						|
		.filter(([_, value]) => value !== undefined && value !== "")
 | 
						|
		.map(
 | 
						|
			([key, value]) =>
 | 
						|
				`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
 | 
						|
		)
 | 
						|
		.join("&");
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/payment/?${query}&all_payments=${allPayments}`,
 | 
						|
		{
 | 
						|
			method: "GET",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	);
 | 
						|
	if (!response.ok) {
 | 
						|
		const errorData = (await response.json()) as ApiError;
 | 
						|
		const errorMessage =
 | 
						|
			errorData.message || errorData.detail || "An error occurred.";
 | 
						|
		const error = new Error(errorMessage);
 | 
						|
		(error as ApiError & { details?: ApiError }).details = errorData; // Attach the errorData to the error object
 | 
						|
		throw error;
 | 
						|
	}
 | 
						|
	const data = (await response.json()) as ApiResponse<Payment>;
 | 
						|
	return data;
 | 
						|
}
 | 
						|
 | 
						|
export async function getTopups(
 | 
						|
	params: GenericGetResponseProps,
 | 
						|
	all_topups = false,
 | 
						|
) {
 | 
						|
	// Build query string from all defined params
 | 
						|
	const query = Object.entries(params)
 | 
						|
		.filter(([_, value]) => value !== undefined && value !== "")
 | 
						|
		.map(
 | 
						|
			([key, value]) =>
 | 
						|
				`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`,
 | 
						|
		)
 | 
						|
		.join("&");
 | 
						|
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/topup/?${query}&all_topups=${all_topups}`,
 | 
						|
		{
 | 
						|
			method: "GET",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	);
 | 
						|
	return handleApiResponse<ApiResponse<Topup>>(response, "getTopups");
 | 
						|
}
 | 
						|
 | 
						|
export async function getTopup({ id }: { id: string }) {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/topup/${id}`,
 | 
						|
		{
 | 
						|
			method: "GET",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	);
 | 
						|
 | 
						|
	return handleApiResponse<Topup>(response, "getTopup");
 | 
						|
}
 | 
						|
 | 
						|
export async function cancelTopup({ id }: { id: string }) {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/topup/${id}/cancel/`,
 | 
						|
		{
 | 
						|
			method: "PATCH",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	);
 | 
						|
	return handleApiResponse<Topup>(response, "cancelTopup");
 | 
						|
}
 | 
						|
 | 
						|
export async function cancelPayment({ id }: { id: string }) {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${id}/cancel/`,
 | 
						|
		{
 | 
						|
			method: "PATCH",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
		},
 | 
						|
	);
 | 
						|
	return handleApiResponse<Payment>(response, "cancelPayment");
 | 
						|
}
 | 
						|
 | 
						|
type UpdatePayment = {
 | 
						|
	id: string;
 | 
						|
	method: "TRANSFER" | "WALLET";
 | 
						|
	benefName?: string;
 | 
						|
	accountNo?: string;
 | 
						|
	absAmount?: string;
 | 
						|
	time?: string;
 | 
						|
};
 | 
						|
export async function verifyPayment({ id, method }: UpdatePayment) {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
	const response = await fetch(
 | 
						|
		`${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${id}/verify/`,
 | 
						|
		{
 | 
						|
			method: "PUT",
 | 
						|
			headers: {
 | 
						|
				"Content-Type": "application/json",
 | 
						|
				Authorization: `Token ${session?.apiToken}`,
 | 
						|
			},
 | 
						|
			body: JSON.stringify({
 | 
						|
				method,
 | 
						|
			}),
 | 
						|
		},
 | 
						|
	);
 | 
						|
	revalidatePath("/payments/[paymentId]", "page");
 | 
						|
	return handleApiResponse<Payment>(response, "updatePayment");
 | 
						|
}
 | 
						|
 | 
						|
export type VerifyDevicePaymentState = {
 | 
						|
	payment?: Payment;
 | 
						|
	message: string;
 | 
						|
	success: boolean;
 | 
						|
	fieldErrors: Record<string, string>;
 | 
						|
	payload?: FormData;
 | 
						|
};
 | 
						|
 | 
						|
export async function verifyDevicePayment(
 | 
						|
	_prevState: VerifyDevicePaymentState,
 | 
						|
	formData: FormData,
 | 
						|
): Promise<VerifyDevicePaymentState> {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
 | 
						|
	// Get the payment ID and method from the form data
 | 
						|
	const paymentId = formData.get("paymentId") as string;
 | 
						|
	const method = formData.get("method") as "TRANSFER" | "WALLET";
 | 
						|
 | 
						|
	if (!paymentId) {
 | 
						|
		return {
 | 
						|
			message: "Payment ID is required",
 | 
						|
			success: false,
 | 
						|
			fieldErrors: { paymentId: "Payment ID is required" },
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	if (!method) {
 | 
						|
		return {
 | 
						|
			message: "Payment method is required",
 | 
						|
			success: false,
 | 
						|
			fieldErrors: { method: "Payment method is required" },
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	try {
 | 
						|
		const response = await fetch(
 | 
						|
			`${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${paymentId}/verify/`,
 | 
						|
			{
 | 
						|
				method: "PUT",
 | 
						|
				headers: {
 | 
						|
					"Content-Type": "application/json",
 | 
						|
					Authorization: `Token ${session?.apiToken}`,
 | 
						|
				},
 | 
						|
				body: JSON.stringify({
 | 
						|
					method,
 | 
						|
				}),
 | 
						|
			},
 | 
						|
		);
 | 
						|
 | 
						|
		const result = await handleApiResponse<Payment>(
 | 
						|
			response,
 | 
						|
			"verifyDevicePayment",
 | 
						|
		);
 | 
						|
 | 
						|
		revalidatePath("/payments/[paymentId]", "page");
 | 
						|
 | 
						|
		return {
 | 
						|
			message:
 | 
						|
				method === "WALLET"
 | 
						|
					? "Payment completed successfully using wallet!"
 | 
						|
					: "Payment verification successful!",
 | 
						|
			success: true,
 | 
						|
			fieldErrors: {},
 | 
						|
			payment: result,
 | 
						|
		};
 | 
						|
	} catch (error: unknown) {
 | 
						|
		if (error instanceof Error) {
 | 
						|
			return {
 | 
						|
				message:
 | 
						|
					error.message || "Payment verification failed. Please try again.",
 | 
						|
				success: false,
 | 
						|
				fieldErrors: {},
 | 
						|
			};
 | 
						|
		} else {
 | 
						|
			return {
 | 
						|
				message: "Payment verification failed.",
 | 
						|
				success: false,
 | 
						|
				fieldErrors: {},
 | 
						|
			};
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
export type VerifyTopupPaymentState = {
 | 
						|
	transaction?: {
 | 
						|
		sourceBank: string;
 | 
						|
		trxDate: string;
 | 
						|
	};
 | 
						|
	message: string;
 | 
						|
	success: boolean;
 | 
						|
	fieldErrors: Record<string, string>;
 | 
						|
	payload?: FormData;
 | 
						|
};
 | 
						|
export async function verifyTopupPayment(
 | 
						|
	_prevState: VerifyTopupPaymentState,
 | 
						|
	formData: FormData,
 | 
						|
): Promise<VerifyTopupPaymentState> {
 | 
						|
	const session = await getServerSession(authOptions);
 | 
						|
 | 
						|
	// Get the topup ID from the form data or use a hidden input
 | 
						|
	const topupId = formData.get("topupId") as string;
 | 
						|
 | 
						|
	if (!topupId) {
 | 
						|
		return {
 | 
						|
			message: "Topup ID is required",
 | 
						|
			success: false,
 | 
						|
			fieldErrors: { topupId: "Topup ID is required" },
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	try {
 | 
						|
		const response = await fetch(
 | 
						|
			`${process.env.SARLINK_API_BASE_URL}/api/billing/topup/${topupId}/verify/`,
 | 
						|
			{
 | 
						|
				method: "PUT",
 | 
						|
				headers: {
 | 
						|
					"Content-Type": "application/json",
 | 
						|
					Authorization: `Token ${session?.apiToken}`,
 | 
						|
				},
 | 
						|
			},
 | 
						|
		);
 | 
						|
 | 
						|
		const result = await handleApiResponse<TopupResponse>(
 | 
						|
			response,
 | 
						|
			"verifyTopupPayment",
 | 
						|
		);
 | 
						|
 | 
						|
		revalidatePath("/top-ups/[topupId]", "page");
 | 
						|
 | 
						|
		return {
 | 
						|
			message: result.message || "Topup payment verified successfully",
 | 
						|
			success: true,
 | 
						|
			fieldErrors: {},
 | 
						|
			transaction: result.transaction,
 | 
						|
		};
 | 
						|
	} catch (error: unknown) {
 | 
						|
		if (error instanceof Error) {
 | 
						|
			return {
 | 
						|
				message:
 | 
						|
					error.message || "Please check your payment details and try again.",
 | 
						|
				success: false,
 | 
						|
				fieldErrors: {},
 | 
						|
			};
 | 
						|
		} else {
 | 
						|
			return {
 | 
						|
				message: "Topup verification failed.",
 | 
						|
				success: false,
 | 
						|
				fieldErrors: {},
 | 
						|
			};
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |