From 9e25da717ba06d36e60aed9d1de4bfff4b446213 Mon Sep 17 00:00:00 2001 From: i701 Date: Sun, 6 Jul 2025 22:37:23 +0500 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20add=20expiry=20label=20to=20ExpiryC?= =?UTF-8?q?ountDown=20component=20in=20TopupPage=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/(dashboard)/payments/[paymentId]/page.tsx | 20 +++++++++++++++---- app/(dashboard)/top-ups/[topupId]/page.tsx | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/(dashboard)/payments/[paymentId]/page.tsx b/app/(dashboard)/payments/[paymentId]/page.tsx index 9f53c3b..1e0b151 100644 --- a/app/(dashboard)/payments/[paymentId]/page.tsx +++ b/app/(dashboard)/payments/[paymentId]/page.tsx @@ -1,11 +1,12 @@ +import { redirect } from "next/navigation"; import { getPayment, getProfile } from "@/actions/payment"; import CancelPaymentButton from "@/components/billing/cancel-payment-button"; +import ExpiryCountDown from "@/components/billing/expiry-time-countdown"; import ClientErrorMessage from "@/components/client-error-message"; import DevicesToPay from "@/components/devices-to-pay"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { tryCatch } from "@/utils/tryCatch"; -import { redirect } from "next/navigation"; export default async function PaymentPage({ params, }: { @@ -40,13 +41,24 @@ export default async function PaymentPage({ {payment?.paid ? "Paid" : "Pending"} {!payment.paid && ( - + payment.is_expired ? ( + + ) : ( + + ) )} - + {!payment.paid && ( + + )}
{!topup.paid && ( - + )}
Date: Sun, 6 Jul 2025 22:38:01 +0500 Subject: [PATCH 2/5] =?UTF-8?q?feat:=20enhance=20payment=20and=20topup=20i?= =?UTF-8?q?nterfaces=20with=20status=20and=20expiration=20details=20?= =?UTF-8?q?=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/payments-table.tsx | 73 +++++++++++++++++++++++------------ components/topups-table.tsx | 25 ------------ lib/backend-types.ts | 5 ++- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/components/payments-table.tsx b/components/payments-table.tsx index 014593a..4b79ec5 100644 --- a/components/payments-table.tsx +++ b/components/payments-table.tsx @@ -59,7 +59,7 @@ export async function PaymentsTable({ Details Duration - + Status Amount @@ -84,6 +84,8 @@ export async function PaymentsTable({ month: "short", day: "2-digit", year: "numeric", + minute: "2-digit", + hour: "2-digit", }, )} @@ -98,16 +100,6 @@ export async function PaymentsTable({ View Details - - {payment.paid ? "Paid" : "Unpaid"} -

Devices

@@ -124,9 +116,30 @@ export async function PaymentsTable({
+ {payment.number_of_months} Months + + + {payment.paid ? ( + + {payment.status} + + ) : payment.is_expired ? ( + Expired + ) : ( + {payment.status} + )} + + {payment.amount.toFixed(2)} @@ -185,6 +198,8 @@ function MobilePaymentDetails({ payment }: { payment: Payment }) { month: "short", day: "2-digit", year: "numeric", + minute: "2-digit", + hour: "2-digit", })} @@ -198,16 +213,6 @@ function MobilePaymentDetails({ payment }: { payment: Payment }) { View Details - - {payment.paid ? "Paid" : "Unpaid"} -

Devices

@@ -226,9 +231,29 @@ function MobilePaymentDetails({ payment }: { payment: Payment }) {

Amount

- - {payment.amount.toFixed(2)} MVR - +
+ + {payment.amount.toFixed(2)} MVR + + + {payment.paid ? ( + + {payment.status} + + ) : payment.is_expired ? ( + Expired + ) : ( + {payment.status} + )} + +
diff --git a/components/topups-table.tsx b/components/topups-table.tsx index f7fb0ab..f85e3eb 100644 --- a/components/topups-table.tsx +++ b/components/topups-table.tsx @@ -103,19 +103,6 @@ export async function TopupsTable({ View Details - {!topup.is_expired && - topup.status !== "CANCELLED" && ( - - {topup.paid ? "Paid" : "Unpaid"} - - )}
@@ -203,18 +190,6 @@ function MobileTopupDetails({ topup }: { topup: Topup }) { View Details - {!topup.is_expired && topup.status !== "CANCELLED" && ( - - {topup.paid ? "Paid" : "Unpaid"} - - )}
diff --git a/lib/backend-types.ts b/lib/backend-types.ts index a42e8f8..1cdfcd5 100644 --- a/lib/backend-types.ts +++ b/lib/backend-types.ts @@ -81,9 +81,12 @@ export interface Payment { paid: boolean; paid_at: string | null; method: string; - expires_at: string | null; + expires_at: string; + is_expired: boolean; created_at: string; updated_at: string; + status: "CANCELLED" | "PENDING" | "PAID"; + mib_reference: string | null; user: number; } From 4797ee8ddee610d2f6060dec91cf9ab66e1d97e3 Mon Sep 17 00:00:00 2001 From: i701 Date: Sun, 6 Jul 2025 22:38:39 +0500 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20add=20expiry=20label=20to=20ExpiryC?= =?UTF-8?q?ountDown=20component=20=E2=9C=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/billing/expiry-time-countdown.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/billing/expiry-time-countdown.tsx b/components/billing/expiry-time-countdown.tsx index a5a7188..59e0ab4 100644 --- a/components/billing/expiry-time-countdown.tsx +++ b/components/billing/expiry-time-countdown.tsx @@ -15,7 +15,7 @@ const HumanizeTimeLeft = (seconds: number) => { return `${minutes}m ${remainingSeconds}s` } -export default function ExpiryCountDown({ expiresAt }: { expiresAt: string }) { +export default function ExpiryCountDown({ expiresAt, expiryLabel }: { expiresAt: string, expiryLabel: string }) { const [timeLeft, setTimeLeft] = useState(calculateTimeLeft(expiresAt)) const [mounted, setMounted] = useState(false) const router = useRouter() @@ -47,7 +47,7 @@ export default function ExpiryCountDown({ expiresAt }: { expiresAt: string }) { {timeLeft ? ( Time left: {HumanizeTimeLeft(timeLeft)} ) : ( - Top up has expired. Please make another topup to add balance to your wallet. + {expiryLabel} has expired. )} {timeLeft > 0 && ( From e9847058493f4f1c3e3db20000b28c6b791c9173 Mon Sep 17 00:00:00 2001 From: i701 Date: Sun, 6 Jul 2025 22:38:55 +0500 Subject: [PATCH 4/5] =?UTF-8?q?refactor:=20update=20cancelPayment=20functi?= =?UTF-8?q?on=20to=20use=20PATCH=20method=20and=20new=20endpoint=20?= =?UTF-8?q?=F0=9F=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- actions/payment.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/actions/payment.ts b/actions/payment.ts index 9b0eef9..82f97df 100644 --- a/actions/payment.ts +++ b/actions/payment.ts @@ -179,24 +179,16 @@ export async function cancelTopup({ id }: { id: string }) { 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}/delete/`, + `${process.env.SARLINK_API_BASE_URL}/api/billing/payment/${id}/cancel/`, { - method: "DELETE", + method: "PATCH", 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; - } - return { message: "Payment successfully canceled." }; + return handleApiResponse(response, "cancelPayment"); } type UpdatePayment = { From 837cc35ad31ae807504659d2588fbe8b889d34b8 Mon Sep 17 00:00:00 2001 From: i701 Date: Sun, 6 Jul 2025 22:39:16 +0500 Subject: [PATCH 5/5] =?UTF-8?q?refactor:=20reorder=20imports=20and=20impro?= =?UTF-8?q?ve=20variable=20naming=20in=20CancelPaymentButton=20component?= =?UTF-8?q?=20=F0=9F=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/billing/cancel-payment-button.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/components/billing/cancel-payment-button.tsx b/components/billing/cancel-payment-button.tsx index 5cb2b50..24b0441 100644 --- a/components/billing/cancel-payment-button.tsx +++ b/components/billing/cancel-payment-button.tsx @@ -1,11 +1,11 @@ "use client"; -import { cancelPayment } from "@/actions/payment"; -import { tryCatch } from "@/utils/tryCatch"; import { Loader2, Trash2 } from "lucide-react"; import { useRouter } from "next/navigation"; import React from "react"; import { toast } from "sonner"; +import { cancelPayment } from "@/actions/payment"; +import { tryCatch } from "@/utils/tryCatch"; import { Button } from "../ui/button"; export default function CancelPaymentButton({ @@ -17,12 +17,16 @@ export default function CancelPaymentButton({