mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-06-06 19:16:19 +00:00
Some checks failed
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 1m23s
- Updated payment verification logic in `actions/payment.ts` to remove unused code and improve clarity. - Enhanced `DevicesToPay` component to handle separate states for wallet and transfer payment verification. - Introduced a new `GetMacAccordion` component to guide users on finding their MAC addresses. - Created a reusable accordion component in `ui/accordion.tsx` for better UI consistency. - Integrated the MAC address guide into the device addition dialog. - Updated Tailwind CSS configuration to include animations for the accordion component. - Added Radix UI Accordion dependency to package.json and package-lock.json. - Improved error handling in API response utility to log unauthorized responses.
202 lines
5.7 KiB
TypeScript
202 lines
5.7 KiB
TypeScript
"use client";
|
||
import { verifyPayment } from "@/actions/payment";
|
||
import {
|
||
Table,
|
||
TableBody,
|
||
TableCaption,
|
||
TableCell,
|
||
TableFooter,
|
||
TableRow,
|
||
} from "@/components/ui/table";
|
||
import type { Payment } from "@/lib/backend-types";
|
||
import type { User } from "@/lib/types/user";
|
||
import {
|
||
BadgeDollarSign,
|
||
Clipboard,
|
||
ClipboardCheck,
|
||
Loader2,
|
||
Wallet,
|
||
} from "lucide-react";
|
||
import { useState } from "react";
|
||
import { toast } from "sonner";
|
||
import { Button } from "./ui/button";
|
||
|
||
export default function DevicesToPay({
|
||
payment,
|
||
user,
|
||
}: { payment?: Payment; user?: User }) {
|
||
const [verifyingWalletPayment, setVerifyingWalletPayment] = useState(false);
|
||
const [verifyingTransferPayment, setVerifyingTransferPayment] = useState(false);
|
||
|
||
|
||
const devices = payment?.devices;
|
||
if (devices?.length === 0) {
|
||
return null;
|
||
}
|
||
// 100+(n−1)×75
|
||
const walletBalance = user?.wallet_balance ?? 0;
|
||
|
||
const isWalletPayVisible = walletBalance > (payment?.amount ?? 0);
|
||
|
||
return (
|
||
<div className="w-full">
|
||
<div className="p-2 flex flex-col gap-2">
|
||
<h3 className="title-bg my-1 p-2 border border-dashed rounded-md font-semibold text-lg">
|
||
{!payment?.paid ? "Devices to pay" : "Devices Paid"}
|
||
</h3>
|
||
<div className="flex flex-col gap-2">
|
||
{devices?.map((device) => (
|
||
<div
|
||
key={device.id}
|
||
className="bg-muted border rounded p-2 flex gap-2 items-center"
|
||
>
|
||
<div className="flex flex-col">
|
||
<div className="text-sm font-medium">{device.name}</div>
|
||
<div className="text-xs text-muted-foreground">
|
||
{device.mac}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
<div className="m-2 flex items-end justify-end p-2 text-sm text-foreground border rounded">
|
||
<Table>
|
||
<TableCaption>
|
||
<div className="max-w-sm mx-auto">
|
||
<p>Please send the following amount to the payment address</p>
|
||
<AccountInfomation
|
||
accName="Baraveli Dev"
|
||
accountNo="90101400028321000"
|
||
/>
|
||
{payment?.paid ? (
|
||
<Button
|
||
size={"lg"}
|
||
variant={"secondary"}
|
||
disabled
|
||
className="dark:text-green-200 text-green-900 bg-green-500/20 uppercase font-semibold"
|
||
>
|
||
Payment Verified
|
||
</Button>
|
||
) : (
|
||
<div className="flex flex-col gap-2">
|
||
{isWalletPayVisible && (
|
||
<Button
|
||
disabled={verifyingWalletPayment || verifyingTransferPayment}
|
||
onClick={async () => {
|
||
setVerifyingWalletPayment(true);
|
||
await verifyPayment({
|
||
method: "WALLET",
|
||
id: payment?.id ?? "",
|
||
});
|
||
setVerifyingWalletPayment(false);
|
||
}}
|
||
variant={"secondary"}
|
||
size={"lg"}
|
||
>
|
||
{verifyingWalletPayment ? "Processing payment..." : "Pay with wallet"}
|
||
<Wallet />
|
||
</Button>
|
||
)}
|
||
<Button
|
||
disabled={verifyingTransferPayment || verifyingWalletPayment}
|
||
onClick={async () => {
|
||
setVerifyingTransferPayment(true);
|
||
try {
|
||
const res = await verifyPayment({
|
||
id: payment?.id ?? "",
|
||
method: "TRANSFER"
|
||
});
|
||
toast.success("Payment verification successful!");
|
||
} catch (error: unknown) {
|
||
if (error instanceof Error) {
|
||
toast.error(error.message);
|
||
} else {
|
||
toast.error("Payment verification failed.");
|
||
}
|
||
} finally {
|
||
setVerifyingTransferPayment(false);
|
||
}
|
||
}}
|
||
size={"lg"}
|
||
className="mb-4"
|
||
>
|
||
{verifyingTransferPayment ? "Processing payment..." : "I have paid"}
|
||
{verifyingTransferPayment ? (
|
||
<Loader2 className="animate-spin" />
|
||
) : (
|
||
<BadgeDollarSign />
|
||
)}
|
||
</Button>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</TableCaption>
|
||
<TableBody className="">
|
||
<TableRow>
|
||
<TableCell>Total Devices</TableCell>
|
||
<TableCell className="text-right text-xl">
|
||
{devices?.length}
|
||
</TableCell>
|
||
</TableRow>
|
||
<TableRow>
|
||
<TableCell>Duration</TableCell>
|
||
<TableCell className="text-right text-xl">
|
||
{payment?.number_of_months} Months
|
||
</TableCell>
|
||
</TableRow>
|
||
</TableBody>
|
||
<TableFooter>
|
||
<TableRow className="">
|
||
<TableCell colSpan={1}>Total Due</TableCell>
|
||
<TableCell className="text-right text-3xl font-bold">
|
||
{payment?.amount?.toFixed(2)}
|
||
</TableCell>
|
||
</TableRow>
|
||
</TableFooter>
|
||
</Table>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
function AccountInfomation({
|
||
accountNo,
|
||
accName,
|
||
}: {
|
||
accountNo: string;
|
||
accName: string;
|
||
}) {
|
||
const [accNo, setAccNo] = useState(false);
|
||
return (
|
||
<div className="justify-start items-start border my-4 flex flex-col gap-2 p-2 rounded-md">
|
||
<h6 className="title-bg uppercase p-2 border rounded w-full font-semibold">
|
||
Account Information
|
||
</h6>
|
||
<div className="border justify-start flex flex-col items-start bg-white/10 w-full p-2 rounded">
|
||
<div className="text-sm font-semibold">Account Name</div>
|
||
<span>{accName}</span>
|
||
</div>
|
||
<div className="border flex justify-between items-start gap-2 bg-white/10 w-full p-2 rounded">
|
||
<div className="flex flex-col items-start justify-start">
|
||
<p className="text-sm font-semibold">Account No</p>
|
||
<span>{accountNo}</span>
|
||
</div>
|
||
<Button
|
||
onClick={() => {
|
||
setTimeout(() => {
|
||
setAccNo(true);
|
||
navigator.clipboard.writeText(accountNo);
|
||
}, 2000);
|
||
toast.success("Account number copied!");
|
||
setAccNo((prev) => !prev);
|
||
}}
|
||
variant={"link"}
|
||
>
|
||
{accNo ? <Clipboard /> : <ClipboardCheck color="green" />}
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|