diff --git a/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/action.ts b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/action.ts new file mode 100644 index 0000000..712f752 --- /dev/null +++ b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/action.ts @@ -0,0 +1,69 @@ +"use server"; + +import { artemis } from "@/lib/prisma"; +import type * as Prisma from "@prisma/client"; +type AimeUserGameLocks = Prisma.PrismaClient; + +export async function getLockedUsers() { + try { + const lockedUsers = await artemis.aime_user_game_locks.findMany({ + select: { + id: true, + user: true, + game: true, + expires_at: true, + extra: true, + }, + }); + + // user = aime_user_game_locks id column + const userIds = lockedUsers.map((lockedUsers) => lockedUsers.user); + + const usersWithNames = await artemis.chuni_profile_data.findMany({ + where: { + user: { + in: userIds, + }, + }, + select: { + user: true, + userName: true, + }, + }); + + const LockedUsernames = lockedUsers.map((lockedUsers) => { + const user = usersWithNames.find((u) => u.user === lockedUsers.user); + return { + ...lockedUsers, + userName: user?.userName || null, + }; + }); + return LockedUsernames; + } catch (error) { + console.error("Error fetching locked users:", error); + return null; + } +} + +export async function deleteUserGameLocks(userId: number) { + try { + const result = await artemis.aime_user_game_locks.deleteMany({ + where: { + user: userId, + }, + }); + + if (result.count > 0) { + console.log( + `Successfully deleted ${result.count} rows for user ${userId}.`, + ); + return { success: true, count: result.count }; + } else { + console.log(`No rows found for user ${userId}.`); + return { success: false, message: `No rows found for user ${userId}.` }; + } + } catch (error) { + console.error("Error deleting user game locks:", error); + return { success: false, message: "Error deleting user game locks." }; + } +} diff --git a/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/columns.tsx b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/columns.tsx new file mode 100644 index 0000000..4a847b5 --- /dev/null +++ b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/columns.tsx @@ -0,0 +1,73 @@ +"use client"; +import { ColumnDef } from "@tanstack/react-table"; +import { aime_user_game_locks } from "@/prisma/schemas/artemis/generated/artemis"; +import { Button } from "@/components/ui/button"; +import { Trash2, UnlockIcon } from "lucide-react"; +import { deleteUserGameLocks } from "./action"; +type chunithm = aime_user_game_locks & { userName: string | null }; + +const handleDelete = async (userId: number) => { + try { + const result = await deleteUserGameLocks(userId); + if (result.success) { + console.log( + `Successfully deleted ${result.count} rows for user ${userId}.`, + ); + } else { + console.error(result.message); + } + } catch (error) { + console.error("Error deleting user game locks:", error); + } +}; +export const columns: ColumnDef[] = [ + { + accessorKey: "Username", + header: "Username", + cell: ({ row }) => ( +
+
+ {row.original.userName || `User ID: ${row.original.user}`}{" "} +
+
+ ), + }, + { + accessorKey: "ExpiresDate", + header: "Expiration Date", + cell: ({ row }) => { + const expirationDate = row.original.expires_at; + const currentDate = new Date(); + + if (!expirationDate) { + return
N/A
; + } + + const expirationDateTime = new Date(expirationDate).getTime(); + const currentDateTime = currentDate.getTime(); + const fifteenMinuteBuffer = 15 * 60 * 1000; + + if (expirationDateTime < currentDateTime - fifteenMinuteBuffer) { + return
Expired
; + } + + return
{new Date(expirationDate).toLocaleDateString()}
; + }, + }, + { + accessorKey: "deletelock", + header: "Remove Lock", + cell: ({ row }) => ( +
+ +
+ ), + }, +]; diff --git a/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/data-table.tsx b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/data-table.tsx new file mode 100644 index 0000000..9fdae0c --- /dev/null +++ b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/data-table.tsx @@ -0,0 +1,106 @@ +"use client"; +// https://github.com/dracor-org/einakter/blob/466ca1663098a16cc1141129a6ba22628135b04c/src/components/Table.tsx#L26 +// used the above for reference on how to fuzzy search +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { + ColumnDef, + SortingState, + getSortedRowModel, + flexRender, + getFilteredRowModel, + getCoreRowModel, + getPaginationRowModel, + useReactTable, +} from "@tanstack/react-table"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import DebouncedInput from "@/components/scoreplaylog/DebouncedInput"; +interface DataTableProps { + columns: ColumnDef[]; + data: TData[]; +} + +export function DataTable({ + columns, + data, +}: DataTableProps) { + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + getSortedRowModel: getSortedRowModel(), + getFilteredRowModel: getFilteredRowModel(), + }); + + return ( +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + ))} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender(cell.column.columnDef.cell, cell.getContext())} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+ + +
+
+ ); +} diff --git a/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/page.tsx b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/page.tsx index d4b26e6..f0ef402 100644 --- a/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/page.tsx +++ b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/page.tsx @@ -1,6 +1,10 @@ -import UnlockUser from "./unlock"; +import { getLockedUsers } from "./action"; +import { DataTable } from "./data-table"; +import { columns } from "./columns"; -const FileExtractionPage = async () => { - return ; +const UnlockUserPage = async () => { + const songs = (await getLockedUsers()) || []; + + return ; }; -export default FileExtractionPage; +export default UnlockUserPage; diff --git a/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/unlock.tsx b/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/unlock.tsx deleted file mode 100644 index f6bf32c..0000000 --- a/app/(authenticated)/(admin)/admin/(admin components)/unlockUser/unlock.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Button } from "@/components/ui/button"; -import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; -import { Input } from "@/components/ui/input"; -import { Label } from "@radix-ui/react-dropdown-menu"; -import React from "react"; - -const GenerateKeychip = () => { - return ( - - - Link New Aime Card - - - -
Current Access Code:
-
-
- - -
- -
-
-
- ); -}; - -export default GenerateKeychip; diff --git a/components/navigationbar/adminnavigation.tsx b/components/navigationbar/adminnavigation.tsx index 4838db7..c68523b 100644 --- a/components/navigationbar/adminnavigation.tsx +++ b/components/navigationbar/adminnavigation.tsx @@ -8,8 +8,8 @@ const NAV_ITEMS = [ { href: "/admin/generateKeychip", label: "Generate Keychip" }, { href: "/admin/unlockUser", label: "Unlock User" }, - { href: "/admin/extraction", label: "Extract Game Files" }, - { href: "/admin/gameversions", label: "Edit Game Version" }, + // { href: "/admin/extraction", label: "Extract Game Files" }, + // { href: "/admin/gameversions", label: "Edit Game Version" }, ]; const AdminSubNavigation = () => {