From a60e9a9c85de2a1e7e9b722ebb4c276161290506 Mon Sep 17 00:00:00 2001 From: i701 Date: Sat, 20 Sep 2025 20:42:14 +0500 Subject: [PATCH] =?UTF-8?q?chore:=20add=20skeletons=20to=20tables=20and=20?= =?UTF-8?q?loading.tsx=20files=20for=20routes=20and=20run=20formatting=20?= =?UTF-8?q?=E2=99=BB=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- actions/auth-actions.ts | 372 +++++----- actions/user-actions.ts | 19 +- app/(dashboard)/agreements/page.tsx | 46 +- .../devices/device-table-skeleton.tsx | 76 -- app/(dashboard)/devices/loading.tsx | 22 + app/(dashboard)/devices/page.tsx | 12 +- app/(dashboard)/parental-control/loading.tsx | 22 + app/(dashboard)/parental-control/page.tsx | 11 +- app/(dashboard)/payments/loading.tsx | 22 + app/(dashboard)/payments/page.tsx | 15 +- app/(dashboard)/top-ups/[topupId]/page.tsx | 128 ++-- app/(dashboard)/top-ups/loading.tsx | 22 + app/(dashboard)/top-ups/page.tsx | 11 +- app/(dashboard)/wallet/page.tsx | 123 ++-- commitlint.config.js | 2 +- components/admin/admin-devices-table.tsx | 302 ++++---- components/admin/admin-topup-form.tsx | 4 +- components/admin/admin-topup-table.tsx | 244 +++---- components/admin/user-payments-table.tsx | 302 ++++---- components/agreement-card.tsx | 55 +- components/auth/signup-form.tsx | 14 +- components/block-device-dialog.tsx | 270 +++---- components/device-card.tsx | 196 +++--- components/device-table-skeleton.tsx | 66 ++ components/devices-for-payment.tsx | 2 - components/devices-table.tsx | 210 +++--- components/number-input.tsx | 104 +-- components/pagination.tsx | 168 ++--- components/payments-table.tsx | 514 +++++++------- components/theme-toggle.tsx | 21 +- components/topup-to-pay.tsx | 274 ++++---- components/topups-table.tsx | 384 +++++----- components/ui/app-sidebar.tsx | 402 +++++------ components/ui/sheet.tsx | 2 +- components/ui/sidebar.tsx | 2 +- components/user-table.tsx | 240 +++---- components/wallet-transactions-table.tsx | 434 ++++++------ components/wallet.tsx | 172 ++--- components/welcome-banner.tsx | 52 +- lib/atoms.ts | 20 +- next.config.ts | 1 + package-lock.json | 664 ++++++++++++++---- package.json | 244 +++---- queries/authentication.ts | 312 ++++---- queries/devices.ts | 2 +- 45 files changed, 3539 insertions(+), 3041 deletions(-) delete mode 100644 app/(dashboard)/devices/device-table-skeleton.tsx create mode 100644 app/(dashboard)/devices/loading.tsx create mode 100644 app/(dashboard)/parental-control/loading.tsx create mode 100644 app/(dashboard)/payments/loading.tsx create mode 100644 app/(dashboard)/top-ups/loading.tsx create mode 100644 components/device-table-skeleton.tsx diff --git a/actions/auth-actions.ts b/actions/auth-actions.ts index d7d65e5..ba5c8ce 100644 --- a/actions/auth-actions.ts +++ b/actions/auth-actions.ts @@ -4,226 +4,226 @@ import { redirect } from "next/navigation"; import { z } from "zod"; import { signUpFormSchema } from "@/lib/schemas"; import { - backendRegister, - checkIdOrPhone, - checkTempIdOrPhone, + backendRegister, + checkIdOrPhone, + checkTempIdOrPhone, } from "@/queries/authentication"; import { handleApiResponse, tryCatch } from "@/utils/tryCatch"; const formSchema = z.object({ - phoneNumber: z - .string() - .regex(/^[7|9][0-9]{2}-[0-9]{4}$/, "Please enter a valid phone number"), + phoneNumber: z + .string() + .regex(/^[7|9][0-9]{2}-[0-9]{4}$/, "Please enter a valid phone number"), }); export type FilterUserResponse = { - ok: boolean; - verified: boolean; + ok: boolean; + verified: boolean; }; export type FilterTempUserResponse = { - ok: boolean; - otp_verified: boolean; - t_verified: boolean; + ok: boolean; + otp_verified: boolean; + t_verified: boolean; }; export async function signin(_previousState: ActionState, formData: FormData) { - const phoneNumber = formData.get("phoneNumber") as string; - const result = formSchema.safeParse({ phoneNumber }); - console.log(phoneNumber); + const phoneNumber = formData.get("phoneNumber") as string; + const result = formSchema.safeParse({ phoneNumber }); + console.log(phoneNumber); - if (!result.success) { - return { - message: result.error.errors[0].message, // Get the error message from Zod - status: "error", - }; - } + if (!result.success) { + return { + message: result.error.errors[0].message, // Get the error message from Zod + status: "error", + }; + } - if (!phoneNumber) { - return { - message: "Please enter a phone number", - status: "error", - }; - } - const FORMATTED_MOBILE_NUMBER: string = `${phoneNumber.split("-").join("")}`; - console.log({ FORMATTED_MOBILE_NUMBER }); + if (!phoneNumber) { + return { + message: "Please enter a phone number", + status: "error", + }; + } + const FORMATTED_MOBILE_NUMBER: string = `${phoneNumber.split("-").join("")}`; + console.log({ FORMATTED_MOBILE_NUMBER }); - const user = await fetch( - `${process.env.SARLINK_API_BASE_URL}/api/auth/users/filter/?mobile=${FORMATTED_MOBILE_NUMBER}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - }, - }, - ); - const userData = (await user.json()) as FilterUserResponse; - console.log({ userData }); - if (!userData.ok) { - redirect(`/auth/signup?phone_number=${phoneNumber}`); - } - if (!userData.verified) { - return { - message: - "Your account is on pending verification. Please wait for a response from admin or contact shihaam.", - status: "error", - }; - } + const user = await fetch( + `${process.env.SARLINK_API_BASE_URL}/api/auth/users/filter/?mobile=${FORMATTED_MOBILE_NUMBER}`, + { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }, + ); + const userData = (await user.json()) as FilterUserResponse; + console.log({ userData }); + if (!userData.ok) { + redirect(`/auth/signup?phone_number=${phoneNumber}`); + } + if (!userData.verified) { + return { + message: + "Your account is on pending verification. Please wait for a response from admin or contact shihaam.", + status: "error", + }; + } - const sendOTPResponse = await fetch( - `${process.env.SARLINK_API_BASE_URL}/auth/mobile/`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - mobile: FORMATTED_MOBILE_NUMBER, - }), - }, - ); - const otpResponse = await sendOTPResponse.json(); - console.log("otpResponse", otpResponse); + const sendOTPResponse = await fetch( + `${process.env.SARLINK_API_BASE_URL}/auth/mobile/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + mobile: FORMATTED_MOBILE_NUMBER, + }), + }, + ); + const otpResponse = await sendOTPResponse.json(); + console.log("otpResponse", otpResponse); - redirect(`/auth/verify-otp?phone_number=${FORMATTED_MOBILE_NUMBER}`); + redirect(`/auth/verify-otp?phone_number=${FORMATTED_MOBILE_NUMBER}`); } export type ActionState = { - status?: string; - payload?: FormData; - errors?: z.typeToFlattenedError< - { - id_card: string; - phone_number: string; - name: string; - atoll_id: string; - island_id: string; - address: string; - dob: Date; - terms: string; - policy: string; - accNo: string; - }, - string - >; - db_error?: string; - error?: string; + status?: string; + payload?: FormData; + errors?: z.typeToFlattenedError< + { + id_card: string; + phone_number: string; + name: string; + atoll_id: string; + island_id: string; + address: string; + dob: Date; + terms: string; + policy: string; + accNo: string; + }, + string + >; + db_error?: string; + error?: string; }; export async function signup(_actionState: ActionState, formData: FormData) { - const data = Object.fromEntries(formData.entries()); - const parsedData = signUpFormSchema.safeParse(data); - // get phone number from /signup?phone_number=999-1231 + const data = Object.fromEntries(formData.entries()); + const parsedData = signUpFormSchema.safeParse(data); + // get phone number from /signup?phone_number=999-1231 - console.log("DATA ON SERVER SIDE", data); + console.log("DATA ON SERVER SIDE", data); - if (!parsedData.success) { - return { - message: "Invalid form data", - payload: formData, - errors: parsedData.error.flatten(), - }; - } - const age = - new Date().getFullYear() - new Date(parsedData.data.dob).getFullYear(); - if (age < 18) { - return { - message: "You must be at least 18 years old to register.", - payload: formData, - db_error: "dob", - }; - } + if (!parsedData.success) { + return { + message: "Invalid form data", + payload: formData, + errors: parsedData.error.flatten(), + }; + } + const age = + new Date().getFullYear() - new Date(parsedData.data.dob).getFullYear(); + if (age < 18) { + return { + message: "You must be at least 18 years old to register.", + payload: formData, + db_error: "dob", + }; + } - const idCardExists = await checkIdOrPhone({ - id_card: parsedData.data.id_card, - }); - if (idCardExists.ok) { - return { - message: "ID card already exists.", - payload: formData, - db_error: "id_card", - }; - } + const idCardExists = await checkIdOrPhone({ + id_card: parsedData.data.id_card, + }); + if (idCardExists.ok) { + return { + message: "ID card already exists.", + payload: formData, + db_error: "id_card", + }; + } - const phoneNumberExists = await checkIdOrPhone({ - phone_number: parsedData.data.phone_number, - }); + const phoneNumberExists = await checkIdOrPhone({ + phone_number: parsedData.data.phone_number, + }); - const tempPhoneNumberExists = await checkTempIdOrPhone({ - phone_number: parsedData.data.phone_number, - }); - if (phoneNumberExists.ok || tempPhoneNumberExists.ok) { - return { - message: "Phone number already exists.", - payload: formData, - db_error: "phone_number", - }; - } + const tempPhoneNumberExists = await checkTempIdOrPhone({ + phone_number: parsedData.data.phone_number, + }); + if (phoneNumberExists.ok || tempPhoneNumberExists.ok) { + return { + message: "Phone number already exists.", + payload: formData, + db_error: "phone_number", + }; + } - const [signupError, signupResponse] = await tryCatch( - backendRegister({ - payload: { - firstname: parsedData.data.name.split(" ")[0], - lastname: parsedData.data.name.split(" ").slice(1).join(" "), - username: parsedData.data.phone_number, - address: parsedData.data.address, - id_card: parsedData.data.id_card, - dob: new Date(parsedData.data.dob).toISOString().split("T")[0], - mobile: parsedData.data.phone_number, - island: Number.parseInt(parsedData.data.island_id), - atoll: Number.parseInt(parsedData.data.atoll_id), - acc_no: parsedData.data.accNo, - terms_accepted: parsedData.data.terms, - policy_accepted: parsedData.data.policy, - }, - }), - ); - if (signupError) { - return { - message: signupError.message, - payload: formData, - db_error: "phone_number", - }; - } - console.log("SIGNUP RESPONSE", signupResponse); + const [signupError, signupResponse] = await tryCatch( + backendRegister({ + payload: { + firstname: parsedData.data.name.split(" ")[0], + lastname: parsedData.data.name.split(" ").slice(1).join(" "), + username: parsedData.data.phone_number, + address: parsedData.data.address, + id_card: parsedData.data.id_card, + dob: new Date(parsedData.data.dob).toISOString().split("T")[0], + mobile: parsedData.data.phone_number, + island: Number.parseInt(parsedData.data.island_id), + atoll: Number.parseInt(parsedData.data.atoll_id), + acc_no: parsedData.data.accNo, + terms_accepted: parsedData.data.terms, + policy_accepted: parsedData.data.policy, + }, + }), + ); + if (signupError) { + return { + message: signupError.message, + payload: formData, + db_error: "phone_number", + }; + } + console.log("SIGNUP RESPONSE", signupResponse); - redirect( - `/auth/verify-otp-registration?phone_number=${encodeURIComponent(signupResponse.t_username)}`, - ); - return { message: "User created successfully", error: "success" }; + redirect( + `/auth/verify-otp-registration?phone_number=${encodeURIComponent(signupResponse.t_username)}`, + ); + return { message: "User created successfully", error: "success" }; } export const sendOtp = async (phoneNumber: string, code: string) => { - // Implement sending OTP code via SMS - console.log("Send OTP server fn", phoneNumber, code); - const respose = await fetch(`${process.env.SMS_API_BASE_URL}/api/sms`, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${process.env.SMS_API_KEY}`, - }, - body: JSON.stringify({ - check_delivery: false, - number: phoneNumber, - message: `Your OTP code is ${code}`, - }), - }); - const data = await respose.json(); - console.log(data); - return data; + // Implement sending OTP code via SMS + console.log("Send OTP server fn", phoneNumber, code); + const respose = await fetch(`${process.env.SMS_API_BASE_URL}/api/sms`, { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${process.env.SMS_API_KEY}`, + }, + body: JSON.stringify({ + check_delivery: false, + number: phoneNumber, + message: `Your OTP code is ${code}`, + }), + }); + const data = await respose.json(); + console.log(data); + return data; }; export async function backendMobileLogin({ mobile }: { mobile: string }) { - const response = await fetch( - `${process.env.SARLINK_API_BASE_URL}/auth/mobile/`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - mobile, - }), - }, - ); - return handleApiResponse<{ detail: string }>(response, "backendMobileLogin"); + const response = await fetch( + `${process.env.SARLINK_API_BASE_URL}/auth/mobile/`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + mobile, + }), + }, + ); + return handleApiResponse<{ detail: string }>(response, "backendMobileLogin"); } diff --git a/actions/user-actions.ts b/actions/user-actions.ts index 09e2d91..9368360 100644 --- a/actions/user-actions.ts +++ b/actions/user-actions.ts @@ -11,14 +11,14 @@ import { handleApiResponse } from "@/utils/tryCatch"; type VerifyUserResponse = | { - ok: boolean; - mismatch_fields: string[] | null; - error: string | null; - detail: string | null; - } + ok: boolean; + mismatch_fields: string[] | null; + error: string | null; + detail: string | null; + } | { - message: boolean; - }; + message: boolean; + }; export async function verifyUser(userId: string) { const session = await getServerSession(authOptions); if (!session?.apiToken) { @@ -129,7 +129,6 @@ export type UpdateUserFormState = { payload?: FormData; }; - export async function updateUser( _prevState: UpdateUserFormState, formData: FormData, @@ -190,7 +189,6 @@ export async function updateUser( }; } - export async function updateUserAgreement( _prevState: UpdateUserFormState, formData: FormData, @@ -258,14 +256,13 @@ export async function adminUserTopup( const description = formData.get("description") as string; const session = await getServerSession(authOptions); - if (!amount) { return { status: false, message: "Amount is required", fieldErrors: { amount: ["Amount is required"], description: [] }, payload: formData, - } + }; } const response = await fetch( `${process.env.SARLINK_API_BASE_URL}/api/billing/admin-topup/`, diff --git a/app/(dashboard)/agreements/page.tsx b/app/(dashboard)/agreements/page.tsx index e014aa9..7496fd2 100644 --- a/app/(dashboard)/agreements/page.tsx +++ b/app/(dashboard)/agreements/page.tsx @@ -3,27 +3,27 @@ import { AgreementCard } from "@/components/agreement-card"; import { tryCatch } from "@/utils/tryCatch"; export default async function Agreements() { - const [error, profile] = await tryCatch(getProfile()); - return ( -
-
-

Agreements

-
-
- {error ? ( -
- An error occurred while fetching agreements: {error.message} -
- ) : ( -
- {profile.agreement ? ( - - ) : ( -
No agreement found.
- )} -
- )} -
-
- ); + const [error, profile] = await tryCatch(getProfile()); + return ( +
+
+

Agreements

+
+
+ {error ? ( +
+ An error occurred while fetching agreements: {error.message} +
+ ) : ( +
+ {profile.agreement ? ( + + ) : ( +
No agreement found.
+ )} +
+ )} +
+
+ ); } diff --git a/app/(dashboard)/devices/device-table-skeleton.tsx b/app/(dashboard)/devices/device-table-skeleton.tsx deleted file mode 100644 index bebafde..0000000 --- a/app/(dashboard)/devices/device-table-skeleton.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { Skeleton } from "@/components/ui/skeleton"; -import { - Table, - TableBody, - TableCell, - TableFooter, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table"; -import { cn } from "@/lib/utils"; - -export default function DevicesTableSkeleton() { - return ( - <> -
- - - - Device Name - MAC Address - # - - - - {Array.from({ length: 10 }).map((_, i) => ( - - - - - - - - - - - - ))} - - - - - - - - - - - -
-
-
- {Array.from({ length: 10 }).map((_, i) => ( - - ))} -
- - ); -} - -function DeviceCardSkeleton() { - return ( -
-
- - - - -
-
- ); -} diff --git a/app/(dashboard)/devices/loading.tsx b/app/(dashboard)/devices/loading.tsx new file mode 100644 index 0000000..b28a7e1 --- /dev/null +++ b/app/(dashboard)/devices/loading.tsx @@ -0,0 +1,22 @@ +import DevicesTableSkeleton from "@/components/device-table-skeleton"; +import { Skeleton } from "@/components/ui/skeleton"; + +export default function LoadingComponent() { + return ( +
+
+ + +
+
+ +
+
+ ); +} diff --git a/app/(dashboard)/devices/page.tsx b/app/(dashboard)/devices/page.tsx index 7b5439f..d095d88 100644 --- a/app/(dashboard)/devices/page.tsx +++ b/app/(dashboard)/devices/page.tsx @@ -1,10 +1,10 @@ import { getServerSession } from "next-auth"; import { Suspense } from "react"; import { authOptions } from "@/app/auth"; +import DevicesTableSkeleton from "@/components/device-table-skeleton"; import { DevicesTable } from "@/components/devices-table"; import DynamicFilter from "@/components/generic-filter"; import AddDeviceDialogForm from "@/components/user/add-device-dialog"; -import DevicesTableSkeleton from "./device-table-skeleton"; export default async function Devices({ searchParams, @@ -53,7 +53,15 @@ export default async function Devices({ ]} /> - }> + + } + > diff --git a/app/(dashboard)/parental-control/loading.tsx b/app/(dashboard)/parental-control/loading.tsx new file mode 100644 index 0000000..b28a7e1 --- /dev/null +++ b/app/(dashboard)/parental-control/loading.tsx @@ -0,0 +1,22 @@ +import DevicesTableSkeleton from "@/components/device-table-skeleton"; +import { Skeleton } from "@/components/ui/skeleton"; + +export default function LoadingComponent() { + return ( +
+
+ + +
+
+ +
+
+ ); +} diff --git a/app/(dashboard)/parental-control/page.tsx b/app/(dashboard)/parental-control/page.tsx index 29ea866..70e02cd 100644 --- a/app/(dashboard)/parental-control/page.tsx +++ b/app/(dashboard)/parental-control/page.tsx @@ -1,4 +1,5 @@ import { Suspense } from "react"; +import DevicesTableSkeleton from "@/components/device-table-skeleton"; import { DevicesTable } from "@/components/devices-table"; import DynamicFilter from "@/components/generic-filter"; @@ -51,7 +52,15 @@ export default async function ParentalControl({ ]} />{" "} - + + } + > +
+ + +
+
+ +
+ + ); +} diff --git a/app/(dashboard)/payments/page.tsx b/app/(dashboard)/payments/page.tsx index c962e1d..0835dd2 100644 --- a/app/(dashboard)/payments/page.tsx +++ b/app/(dashboard)/payments/page.tsx @@ -1,4 +1,5 @@ import { Suspense } from "react"; +import DevicesTableSkeleton from "@/components/device-table-skeleton"; import DynamicFilter from "@/components/generic-filter"; import { PaymentsTable } from "@/components/payments-table"; @@ -14,8 +15,8 @@ export default async function Payments({ return (
-
-

My Payments

+
+

My Subscriptions

{" "}
- + + } + >
diff --git a/app/(dashboard)/top-ups/[topupId]/page.tsx b/app/(dashboard)/top-ups/[topupId]/page.tsx index a36e23f..8bc9827 100644 --- a/app/(dashboard)/top-ups/[topupId]/page.tsx +++ b/app/(dashboard)/top-ups/[topupId]/page.tsx @@ -9,72 +9,72 @@ import { TextShimmer } from "@/components/ui/text-shimmer"; import { cn } from "@/lib/utils"; import { tryCatch } from "@/utils/tryCatch"; export default async function TopupPage({ - params, + params, }: { - params: Promise<{ topupId: string }>; + params: Promise<{ topupId: string }>; }) { - const topupId = (await params).topupId; - const [error, topup] = await tryCatch(getTopup({ id: topupId })); - if (error) { - if (error.message === "Invalid token.") redirect("/auth/signin"); - return ; - } + const topupId = (await params).topupId; + const [error, topup] = await tryCatch(getTopup({ id: topupId })); + if (error) { + if (error.message === "Invalid token.") redirect("/auth/signin"); + return ; + } - return ( -
-
-

Topup

-
- {!topup.is_expired && topup.paid && topup.status !== "PENDING" && ( - - )} - {topup.status === "PENDING" && !topup.is_expired && ( - - )} + return ( +
+
+

Topup

+
+ {!topup.is_expired && topup.paid && topup.status !== "PENDING" && ( + + )} + {topup.status === "PENDING" && !topup.is_expired && ( + + )} - {!topup.paid && - (topup.is_expired ? ( - - ) : topup.status === "PENDING" ? ( - - ) : topup.status === "CANCELLED" ? ( - - ) : ( - "" - ))} -
-
- {!topup.paid && topup.status === "PENDING" && !topup.is_expired && ( - - )} -
- -
-
- ); + {!topup.paid && + (topup.is_expired ? ( + + ) : topup.status === "PENDING" ? ( + + ) : topup.status === "CANCELLED" ? ( + + ) : ( + "" + ))} +
+
+ {!topup.paid && topup.status === "PENDING" && !topup.is_expired && ( + + )} +
+ +
+
+ ); } diff --git a/app/(dashboard)/top-ups/loading.tsx b/app/(dashboard)/top-ups/loading.tsx new file mode 100644 index 0000000..8788ddc --- /dev/null +++ b/app/(dashboard)/top-ups/loading.tsx @@ -0,0 +1,22 @@ +import DevicesTableSkeleton from "@/components/device-table-skeleton"; +import { Skeleton } from "@/components/ui/skeleton"; + +export default function LoadingComponent() { + return ( +
+
+ + +
+
+ +
+
+ ); +} diff --git a/app/(dashboard)/top-ups/page.tsx b/app/(dashboard)/top-ups/page.tsx index eaf1403..6f8cf4d 100644 --- a/app/(dashboard)/top-ups/page.tsx +++ b/app/(dashboard)/top-ups/page.tsx @@ -1,4 +1,5 @@ import { Suspense } from "react"; +import DevicesTableSkeleton from "@/components/device-table-skeleton"; import DynamicFilter from "@/components/generic-filter"; import { TopupsTable } from "@/components/topups-table"; @@ -78,7 +79,15 @@ export default async function Topups({ ]} />
- + + } + > diff --git a/app/(dashboard)/wallet/page.tsx b/app/(dashboard)/wallet/page.tsx index f01ee30..69411f8 100644 --- a/app/(dashboard)/wallet/page.tsx +++ b/app/(dashboard)/wallet/page.tsx @@ -1,63 +1,78 @@ import { Suspense } from "react"; +import DevicesTableSkeleton from "@/components/device-table-skeleton"; import DynamicFilter from "@/components/generic-filter"; import { WalletTransactionsTable } from "@/components/wallet-transactions-table"; export default async function Wallet({ - searchParams, + searchParams, }: { - searchParams: Promise<{ - query: string; - page: number; - sortBy: string; - status: string; - }>; + searchParams: Promise<{ + query: string; + page: number; + sortBy: string; + status: string; + }>; }) { - const query = (await searchParams)?.query || ""; + const query = (await searchParams)?.query || ""; - return ( -
-
-

Transaction History

-
-
- -
- - - -
- ); + return ( +
+
+

Transaction History

+
+
+ +
+ + } + > + + +
+ ); } diff --git a/commitlint.config.js b/commitlint.config.js index 2291173..c121e65 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,3 +1,3 @@ export default { - extends: ['@commitlint/config-conventional'] + extends: ["@commitlint/config-conventional"], }; diff --git a/components/admin/admin-devices-table.tsx b/components/admin/admin-devices-table.tsx index 818380a..6e34693 100644 --- a/components/admin/admin-devices-table.tsx +++ b/components/admin/admin-devices-table.tsx @@ -4,13 +4,13 @@ import { redirect } from "next/navigation"; import { getServerSession } from "next-auth"; import { authOptions } from "@/app/auth"; import { - Table, - TableBody, - TableCell, - TableFooter, - TableHead, - TableHeader, - TableRow, + Table, + TableBody, + TableCell, + TableFooter, + TableHead, + TableHeader, + TableRow, } from "@/components/ui/table"; import { cn } from "@/lib/utils"; import { getDevices } from "@/queries/devices"; @@ -20,155 +20,155 @@ import ClientErrorMessage from "../client-error-message"; import Pagination from "../pagination"; export async function AdminDevicesTable({ - searchParams, + searchParams, }: { - searchParams: Promise<{ - [key: string]: unknown; - }>; + searchParams: Promise<{ + [key: string]: unknown; + }>; }) { - const resolvedParams = await searchParams; - const session = await getServerSession(authOptions); - const isAdmin = session?.user?.is_admin; + const resolvedParams = await searchParams; + const session = await getServerSession(authOptions); + const isAdmin = session?.user?.is_admin; - const page = Number.parseInt(resolvedParams.page as string) || 1; - const limit = 10; - const offset = (page - 1) * limit; + const page = Number.parseInt(resolvedParams.page as string) || 1; + const limit = 10; + const offset = (page - 1) * limit; - // Build params object for getDevices - const apiParams: Record = {}; - for (const [key, value] of Object.entries(resolvedParams)) { - if (value !== undefined && value !== "") { - apiParams[key] = typeof value === "number" ? value : String(value); - } - } - apiParams.limit = limit; - apiParams.offset = offset; + // Build params object for getDevices + const apiParams: Record = {}; + for (const [key, value] of Object.entries(resolvedParams)) { + if (value !== undefined && value !== "") { + apiParams[key] = typeof value === "number" ? value : String(value); + } + } + apiParams.limit = limit; + apiParams.offset = offset; - const [error, devices] = await tryCatch(getDevices(apiParams, true)); - if (error) { - if (error.message === "UNAUTHORIZED") { - redirect("/auth/signin"); - } else { - return ; - } - } - const { meta, data } = devices; - return ( -
- {data?.length === 0 ? ( -
-

No devices.

-
- ) : ( - <> -
- - - - Device Name - User - MAC Address - Vendor - # - - - - {data?.map((device) => ( - - -
- - {device.name} - - {device.is_active ? ( -
- Active until{" "} - - {new Date( - device.expiry_date || "", - ).toLocaleDateString("en-US", { - month: "short", - day: "2-digit", - year: "numeric", - })} - -
- ) : ( -

- Device Inactive -

- )} - {device.has_a_pending_payment && ( - - - Payment Pending{" "} - - - - )} + const [error, devices] = await tryCatch(getDevices(apiParams, true)); + if (error) { + if (error.message === "UNAUTHORIZED") { + redirect("/auth/signin"); + } else { + return ; + } + } + const { meta, data } = devices; + return ( +
+ {data?.length === 0 ? ( +
+

No devices.

+
+ ) : ( + <> +
+
+ + + Device Name + User + MAC Address + Vendor + # + + + + {data?.map((device) => ( + + +
+ + {device.name} + + {device.is_active ? ( +
+ Active until{" "} + + {new Date( + device.expiry_date || "", + ).toLocaleDateString("en-US", { + month: "short", + day: "2-digit", + year: "numeric", + })} + +
+ ) : ( +

+ Device Inactive +

+ )} + {device.has_a_pending_payment && ( + + + Payment Pending{" "} + + + + )} - {device.blocked_by === "ADMIN" && device.blocked && ( -
- Comment -

- {device?.reason_for_blocking} -

-
- )} -
-
- -
- {device?.user?.name} - - {device?.user?.id_card} - -
-
- {device.mac} - - {device?.vendor} - - - {!device.has_a_pending_payment && ( - - )} - -
- ))} -
- - - - {meta?.total === 1 ? ( -

Total {meta?.total} device.

- ) : ( -

- Total {meta?.total} devices. -

- )} -
-
-
-
-
+ {device.blocked_by === "ADMIN" && device.blocked && ( +
+ Comment +

+ {device?.reason_for_blocking} +

+
+ )} +
+ + +
+ {device?.user?.name} + + {device?.user?.id_card} + +
+
+ {device.mac} + + {device?.vendor} + + + {!device.has_a_pending_payment && ( + + )} + + + ))} + + + + + {meta?.total === 1 ? ( +

Total {meta?.total} device.

+ ) : ( +

+ Total {meta?.total} devices. +

+ )} +
+
+
+ + - - - )} - - ); + + + )} + + ); } diff --git a/components/admin/admin-topup-form.tsx b/components/admin/admin-topup-form.tsx index 397d1f1..9703b27 100644 --- a/components/admin/admin-topup-form.tsx +++ b/components/admin/admin-topup-form.tsx @@ -104,7 +104,9 @@ export default function AddTopupDialogForm({ user_id }: { user_id?: string }) {