mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-07-02 03:38:22 +00:00
Enhance payment processing and user interaction features
- Updated createPayment function to log payment data more clearly. - Introduced verifyPayment function for validating payments via an external API. - Enhanced DevicesToPay component to include user information and payment verification functionality. - Added formatDate utility for consistent date formatting across the application. - Updated Prisma schema to include account number for users. - Refactored layout and device cart components for improved user experience and responsiveness.
This commit is contained in:
@ -59,7 +59,7 @@ export function DeviceCartDrawer({
|
||||
} else {
|
||||
setMessage("");
|
||||
}
|
||||
setTotal(baseAmount + (devices.length - 1) * discountPercentage);
|
||||
setTotal(baseAmount + ((devices.length + 1) - 1) * discountPercentage);
|
||||
}, [months, devices.length, baseAmount, discountPercentage]);
|
||||
|
||||
if (pathname === "/payment") {
|
||||
|
@ -1,3 +1,5 @@
|
||||
'use client'
|
||||
import { verifyPayment } from "@/actions/payment";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@ -5,35 +7,50 @@ import {
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TableRow,
|
||||
} from "@/components/ui/table"
|
||||
import type { BillFormula, Prisma } from "@prisma/client"
|
||||
import React from 'react'
|
||||
|
||||
} from "@/components/ui/table";
|
||||
import { formatDate } from "@/lib/utils";
|
||||
import type { BillFormula, Prisma, User } from "@prisma/client";
|
||||
import { Clipboard, ClipboardCheck, Loader2, Wallet } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { Button } from "./ui/button";
|
||||
|
||||
type PaymentWithDevices = Prisma.PaymentGetPayload<{
|
||||
include: {
|
||||
devices: true
|
||||
}
|
||||
}>
|
||||
devices: true;
|
||||
};
|
||||
}>;
|
||||
|
||||
export default function DevicesToPay({ billFormula, payment }: { billFormula?: BillFormula, payment?: PaymentWithDevices }) {
|
||||
const devices = payment?.devices
|
||||
export default function DevicesToPay({
|
||||
billFormula,
|
||||
payment,
|
||||
user
|
||||
}: { billFormula?: BillFormula; payment?: PaymentWithDevices, user?: User }) {
|
||||
const [verifying, setVerifying] = useState(false)
|
||||
|
||||
const devices = payment?.devices;
|
||||
if (devices?.length === 0) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
const baseAmount = billFormula?.baseAmount ?? 100
|
||||
const discountPercentage = billFormula?.discountPercentage ?? 75
|
||||
const baseAmount = billFormula?.baseAmount ?? 100;
|
||||
const discountPercentage = billFormula?.discountPercentage ?? 75;
|
||||
// 100+(n−1)×75
|
||||
const total = baseAmount + (devices?.length ?? 1 - 1) * discountPercentage
|
||||
const total = baseAmount + (devices?.length ?? 1 - 1) * discountPercentage;
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className='w-full'>
|
||||
<div className='p-2 flex flex-col gap-2'>
|
||||
<h3 className='title-bg my-1 font-semibold text-lg'>
|
||||
{!payment?.paid ? 'Devices to pay' : 'Devices Paid'}
|
||||
<div className="w-full">
|
||||
<div className="p-2 flex flex-col gap-2">
|
||||
<h3 className="title-bg my-1 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
|
||||
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">
|
||||
@ -44,9 +61,49 @@ export default function DevicesToPay({ billFormula, payment }: { billFormula?: B
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className='m-2 flex items-end justify-end p-2 text-sm text-foreground border rounded'>
|
||||
<div className="m-2 flex items-end justify-end p-2 text-sm text-foreground border rounded">
|
||||
<Table>
|
||||
<TableCaption>Please send the following amount to the payment address</TableCaption>
|
||||
<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="text-green-400 bg-green-800">Payment Verified</Button>
|
||||
) : (
|
||||
<Button
|
||||
disabled={verifying}
|
||||
onClick={async () => {
|
||||
setVerifying(true);
|
||||
const res = await verifyPayment({
|
||||
paymentId: payment?.id,
|
||||
benefName: user?.name ?? "",
|
||||
accountNo: user?.accNo ?? "",
|
||||
absAmount: String(total),
|
||||
time: formatDate(new Date(payment?.createdAt || "")),
|
||||
});
|
||||
setVerifying(false);
|
||||
switch (true) {
|
||||
case res.success === true:
|
||||
toast.success(res.message);
|
||||
break;
|
||||
case res.success === false:
|
||||
toast.error(res.message);
|
||||
break;
|
||||
default:
|
||||
toast.error("Unexpected error occurred.");
|
||||
}
|
||||
}}
|
||||
size={"lg"} className="mb-4">
|
||||
{verifying ? "Verifying..." : "Verify Payment"}
|
||||
{verifying ? <Loader2 className="animate-spin" /> : <Wallet />}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
</div>
|
||||
</TableCaption>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableCell>Total Devices</TableCell>
|
||||
@ -62,6 +119,44 @@ export default function DevicesToPay({ billFormula, payment }: { billFormula?: B
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user