mirror of
				https://github.com/i701/sarlink-portal.git
				synced 2025-10-28 20:23:09 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			367 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			367 lines
		
	
	
		
			9.5 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 type { User } from "@/lib/types/user";
 | |
| 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) {
 | |
| 	// 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}`,
 | |
| 		{
 | |
| 			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) {
 | |
| 
 | |
| 	// 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}`,
 | |
| 		{
 | |
| 			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: {},
 | |
| 			};
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 |