mirror of
https://github.com/i701/sarlink-portal.git
synced 2025-02-22 17:42:00 +00:00
Enhance payment processing and device management features
- Updated `package.json` to add a new script for pushing Prisma database changes. - Refactored payment processing functions to include payment method handling for both wallet and transfer options. - Improved `DevicesTable` and `AdminDevicesTable` components to support new payment method display and user association. - Updated Prisma schema to introduce a new `PaymentType` enum and modified the `Payment` model to include a `method` field. - Enhanced UI components to improve user experience in displaying payment and device information. These changes improve the overall functionality and maintainability of the application, particularly in payment processing and device management.
This commit is contained in:
parent
0a63e4337e
commit
1a195d2307
@ -78,11 +78,15 @@ async function processWalletPayment(
|
|||||||
data: {
|
data: {
|
||||||
paid: true,
|
paid: true,
|
||||||
paidAt: new Date(),
|
paidAt: new Date(),
|
||||||
|
method: "WALLET",
|
||||||
devices: {
|
devices: {
|
||||||
updateMany: {
|
updateMany: payment.devices.map((device) => ({
|
||||||
where: { paymentId: payment.id },
|
where: { id: device.id },
|
||||||
data: { isActive: true, expiryDate: expiryDate },
|
data: {
|
||||||
|
isActive: true,
|
||||||
|
expiryDate: expiryDate,
|
||||||
},
|
},
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
@ -136,11 +140,15 @@ async function verifyExternalPayment(
|
|||||||
data: {
|
data: {
|
||||||
paid: true,
|
paid: true,
|
||||||
paidAt: new Date(),
|
paidAt: new Date(),
|
||||||
|
method: "TRANSFER",
|
||||||
devices: {
|
devices: {
|
||||||
updateMany: {
|
updateMany: payment.devices.map((device) => ({
|
||||||
where: { paymentId: payment.id },
|
where: { id: device.id },
|
||||||
data: { isActive: true, expiryDate: expiryDate },
|
data: {
|
||||||
|
isActive: true,
|
||||||
|
expiryDate: expiryDate,
|
||||||
},
|
},
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -177,16 +185,19 @@ export async function verifyPayment(data: VerifyPaymentType) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if (data.type === "WALLET") {
|
if (data.type === "WALLET") {
|
||||||
|
console.log("WALLET");
|
||||||
await processWalletPayment(user, payment, Number(data.absAmount));
|
await processWalletPayment(user, payment, Number(data.absAmount));
|
||||||
redirect("/payments");
|
redirect("/payments");
|
||||||
}
|
}
|
||||||
|
if (data.type === "TRANSFER") {
|
||||||
|
console.log({ data, payment });
|
||||||
const verificationResult = await verifyExternalPayment(data, payment);
|
const verificationResult = await verifyExternalPayment(data, payment);
|
||||||
await updateDevices(payment);
|
await updateDevices(payment);
|
||||||
|
|
||||||
revalidatePath("/payment[paymentId]");
|
revalidatePath("/payment[paymentId]");
|
||||||
|
|
||||||
return verificationResult;
|
return verificationResult;
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Payment verification failed:", error);
|
console.error("Payment verification failed:", error);
|
||||||
throw error; // Re-throw to handle at a higher level
|
throw error; // Re-throw to handle at a higher level
|
||||||
|
@ -75,7 +75,10 @@ export async function AdminDevicesTable({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
include: {
|
||||||
|
User: true,
|
||||||
|
payments: true,
|
||||||
|
},
|
||||||
skip: offset,
|
skip: offset,
|
||||||
take: limit,
|
take: limit,
|
||||||
orderBy: {
|
orderBy: {
|
||||||
@ -97,6 +100,7 @@ export async function AdminDevicesTable({
|
|||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Device Name</TableHead>
|
<TableHead>Device Name</TableHead>
|
||||||
|
<TableHead>User</TableHead>
|
||||||
<TableHead>MAC Address</TableHead>
|
<TableHead>MAC Address</TableHead>
|
||||||
<TableHead>isActive</TableHead>
|
<TableHead>isActive</TableHead>
|
||||||
<TableHead>blocked</TableHead>
|
<TableHead>blocked</TableHead>
|
||||||
@ -115,6 +119,8 @@ export async function AdminDevicesTable({
|
|||||||
>
|
>
|
||||||
{device.name}
|
{device.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
{device.isActive && (
|
||||||
|
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">
|
||||||
Active until{" "}
|
Active until{" "}
|
||||||
{new Date().toLocaleDateString("en-US", {
|
{new Date().toLocaleDateString("en-US", {
|
||||||
@ -123,6 +129,8 @@ export async function AdminDevicesTable({
|
|||||||
year: "numeric",
|
year: "numeric",
|
||||||
})}
|
})}
|
||||||
</span>
|
</span>
|
||||||
|
)}
|
||||||
|
|
||||||
{device.blocked && (
|
{device.blocked && (
|
||||||
<div className="p-2 rounded border my-2">
|
<div className="p-2 rounded border my-2">
|
||||||
<span>Comment: </span>
|
<span>Comment: </span>
|
||||||
@ -134,6 +142,8 @@ export async function AdminDevicesTable({
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
<TableCell className="font-medium">{device.User?.name}</TableCell>
|
||||||
|
|
||||||
<TableCell className="font-medium">{device.mac}</TableCell>
|
<TableCell className="font-medium">{device.mac}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{device.isActive ? "Active" : "Inactive"}
|
{device.isActive ? "Active" : "Inactive"}
|
||||||
@ -159,7 +169,7 @@ export async function AdminDevicesTable({
|
|||||||
</TableBody>
|
</TableBody>
|
||||||
<TableFooter>
|
<TableFooter>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={5}>
|
<TableCell colSpan={7}>
|
||||||
{query.length > 0 && (
|
{query.length > 0 && (
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Showing {devices.length} locations for "{query}
|
Showing {devices.length} locations for "{query}
|
||||||
|
@ -139,14 +139,13 @@ export async function UsersPaymentsTable({
|
|||||||
<TableCaption>Table of all users.</TableCaption>
|
<TableCaption>Table of all users.</TableCaption>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>Name</TableHead>
|
<TableHead>Devices paid</TableHead>
|
||||||
<TableHead>ID Card</TableHead>
|
<TableHead>User</TableHead>
|
||||||
<TableHead>Atoll</TableHead>
|
<TableHead>Amount</TableHead>
|
||||||
<TableHead>Island</TableHead>
|
<TableHead>Duration</TableHead>
|
||||||
<TableHead>House Name</TableHead>
|
<TableHead>Payment Status</TableHead>
|
||||||
<TableHead>Status</TableHead>
|
<TableHead>Payment Method</TableHead>
|
||||||
<TableHead>Dob</TableHead>
|
<TableHead>Paid At</TableHead>
|
||||||
<TableHead>Phone Number</TableHead>
|
|
||||||
<TableHead>Action</TableHead>
|
<TableHead>Action</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
@ -156,7 +155,15 @@ export async function UsersPaymentsTable({
|
|||||||
className={`${payment.paid && "title-bg dark:bg-black"}`}
|
className={`${payment.paid && "title-bg dark:bg-black"}`}
|
||||||
key={payment.id}
|
key={payment.id}
|
||||||
>
|
>
|
||||||
<TableCell className="font-medium">{payment.user.name}</TableCell>
|
<TableCell className="font-medium">
|
||||||
|
<ol className="list-disc list-inside text-sm">
|
||||||
|
{payment.devices.map((device) => (
|
||||||
|
<li key={device.id} className="text-sm text-muted-foreground">
|
||||||
|
{device.name}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
</TableCell>
|
||||||
<TableCell className="font-medium">{payment.user.id_card}</TableCell>
|
<TableCell className="font-medium">{payment.user.id_card}</TableCell>
|
||||||
<TableCell>{payment.user?.name}</TableCell>
|
<TableCell>{payment.user?.name}</TableCell>
|
||||||
<TableCell>{payment.user?.name}</TableCell>
|
<TableCell>{payment.user?.name}</TableCell>
|
||||||
|
@ -6,10 +6,10 @@ import Link from "next/link";
|
|||||||
import { signup } from "@/actions/auth-actions";
|
import { signup } from "@/actions/auth-actions";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import type { Island, Prisma } from "@prisma/client";
|
import type { Island, Prisma } from "@prisma/client";
|
||||||
import { Loader } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import { useSearchParams } from "next/navigation";
|
import { useSearchParams } from "next/navigation";
|
||||||
import { useActionState } from "react";
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import { useActionState } from "react";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
@ -308,7 +308,7 @@ export default function SignUpForm({ atolls }: { atolls: AtollWithIslands[] }) {
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
<Button disabled={isPending} className="mt-4 w-full" type="submit">
|
<Button disabled={isPending} className="mt-4 w-full" type="submit">
|
||||||
{isPending ? <Loader className="animate-spin" /> : "Submit"}
|
{isPending ? <Loader2 className="animate-spin" /> : "Submit"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -51,9 +51,11 @@ export async function DevicesTable({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
NOT: {
|
NOT: {
|
||||||
payment: {
|
payments: {
|
||||||
|
some: {
|
||||||
paid: false
|
paid: false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
isActive: isAdmin ? undefined : parentalControl,
|
isActive: isAdmin ? undefined : parentalControl,
|
||||||
blocked: isAdmin ? undefined : parentalControl !== undefined ? undefined : false,
|
blocked: isAdmin ? undefined : parentalControl !== undefined ? undefined : false,
|
||||||
@ -82,8 +84,10 @@ export async function DevicesTable({
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
NOT: {
|
NOT: {
|
||||||
payment: {
|
payments: {
|
||||||
|
some: {
|
||||||
paid: false
|
paid: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
isActive: parentalControl,
|
isActive: parentalControl,
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
"build": "bunx prisma migrate deploy && bunx prisma generate && bunx prisma db push && next build",
|
"build": "bunx prisma migrate deploy && bunx prisma generate && bunx prisma db push && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"studio": "bunx prisma studio"
|
"studio": "bunx prisma studio",
|
||||||
|
"push": "bunx prisma db push"
|
||||||
},
|
},
|
||||||
"prisma": {
|
"prisma": {
|
||||||
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
|
"seed": "ts-node --compiler-options {\"module\":\"CommonJS\"} prisma/seed.ts"
|
||||||
|
5
prisma/migrations/20250108172258_add/migration.sql
Normal file
5
prisma/migrations/20250108172258_add/migration.sql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "PaymentType" AS ENUM ('WALLET', 'TRANSFER');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Payment" ADD COLUMN "method" "PaymentType" NOT NULL DEFAULT 'TRANSFER';
|
28
prisma/migrations/20250108173116_change/migration.sql
Normal file
28
prisma/migrations/20250108173116_change/migration.sql
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `paymentId` on the `Device` table. All the data in the column will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- DropForeignKey
|
||||||
|
ALTER TABLE "Device" DROP CONSTRAINT "Device_paymentId_fkey";
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Device" DROP COLUMN "paymentId";
|
||||||
|
|
||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "_DeviceToPayment" (
|
||||||
|
"A" TEXT NOT NULL,
|
||||||
|
"B" TEXT NOT NULL,
|
||||||
|
|
||||||
|
CONSTRAINT "_DeviceToPayment_AB_pkey" PRIMARY KEY ("A","B")
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE INDEX "_DeviceToPayment_B_index" ON "_DeviceToPayment"("B");
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_DeviceToPayment" ADD CONSTRAINT "_DeviceToPayment_A_fkey" FOREIGN KEY ("A") REFERENCES "Device"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||||
|
|
||||||
|
-- AddForeignKey
|
||||||
|
ALTER TABLE "_DeviceToPayment" ADD CONSTRAINT "_DeviceToPayment_B_fkey" FOREIGN KEY ("B") REFERENCES "Payment"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
@ -115,6 +115,11 @@ enum Blocker {
|
|||||||
PARENT
|
PARENT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PaymentType {
|
||||||
|
WALLET
|
||||||
|
TRANSFER
|
||||||
|
}
|
||||||
|
|
||||||
model Device {
|
model Device {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
@ -129,8 +134,7 @@ model Device {
|
|||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
User User? @relation(fields: [userId], references: [id])
|
User User? @relation(fields: [userId], references: [id])
|
||||||
userId String?
|
userId String?
|
||||||
payment Payment? @relation(fields: [paymentId], references: [id])
|
payments Payment[]
|
||||||
paymentId String?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model Payment {
|
model Payment {
|
||||||
@ -140,6 +144,7 @@ model Payment {
|
|||||||
paid Boolean @default(false)
|
paid Boolean @default(false)
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
paidAt DateTime?
|
paidAt DateTime?
|
||||||
|
method PaymentType @default(TRANSFER)
|
||||||
expiresAt DateTime?
|
expiresAt DateTime?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
|
Loading…
x
Reference in New Issue
Block a user