Loading next.config.ts +5 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,11 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ experimental: { serverActions: { bodySizeLimit: "2mb", }, }, }; export default nextConfig; src/app/Admin/APIKEY/ApiKeyListClient.tsx +22 −14 Original line number Diff line number Diff line 'use client'; import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState, useMemo } from "react"; import { deleteApiKey, saveEnabledApiKey } from "./actions"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { ClientApiKeyListProps, ApiKey } from "@/types/CustomTypes"; export default function ApiKeyListClient({ data }: { data: any }) { export default function ApiKeyListClient({ data }: ClientApiKeyListProps) { const router = useRouter(); const ApiKeys = Array.isArray(data?.apikeys) ? data.apikeys : []; const ApiKeys: ApiKey[] = useMemo(() => Array.isArray(data?.apikeys) ? data.apikeys : [], [data]); const [selectedApiKeys, setselectedApiKeys] = useState<Record<number, boolean>>({}); const handleSelect = (id: number, checked: boolean) => { Loading @@ -15,7 +18,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { const [enabledStates, setEnabledStates] = useState<Record<number, boolean>>(() => { const state: Record<number, boolean> = {}; ApiKeys.forEach((ApiKey: any) => { ApiKeys.forEach((ApiKey) => { state[ApiKey.id] = !!ApiKey.is_valid; }); return state; Loading @@ -26,7 +29,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { useEffect(() => { if (lastToggled.current) { const toggledId = lastToggled.current.id; const apiKeysExists = ApiKeys.some((ApiKey: any) => ApiKey.id === toggledId); const apiKeysExists = ApiKeys.some((ApiKey) => ApiKey.id === toggledId); if (!apiKeysExists) { setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: `Api Key with id ${toggledId} not found.`, type: 'danger' }]); lastToggled.current = null; Loading @@ -36,14 +39,19 @@ export default function ApiKeyListClient({ data }: { data: any }) { try { await saveEnabledApiKey(toggledId, lastToggled.current!.value); setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: `Api Key ${toggledId} updated successfully.`, type: 'success' }]); } catch (err: any) { setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: err.message || `Failed to update api key ${toggledId}.`, type: 'danger' }]); } catch (error: unknown) { let msg = `Failed to update api key ${toggledId}.`; if (error instanceof Error) { msg = (error as { message: string }).message; } setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: msg, type: 'danger' }]); } finally { lastToggled.current = null; } })(); } }, [enabledStates]); }, [enabledStates, ApiKeys]); const handleToggle = (id: number) => { setEnabledStates((prev) => { Loading Loading @@ -72,7 +80,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { setselectedApiKeys({}); router.refresh(); } catch (err) { } catch { setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: 'Failed to delete selected languages.', type: 'danger' }]); setselectedApiKeys({}); } Loading Loading @@ -132,7 +140,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { </tr> </thead> <tbody> {ApiKeys && ApiKeys.map((apikey: any) => ( {ApiKeys && ApiKeys.map((apikey) => ( <tr key={apikey.id}> <td> <input Loading Loading @@ -160,8 +168,8 @@ export default function ApiKeyListClient({ data }: { data: any }) { </div> </td> <td>{apikey.valid_until}</td> <td>{apikey.last_usage}</td> <td>{apikey.valid_until instanceof Date ? apikey.valid_until.toLocaleString() : String(apikey.valid_until || "")}</td> <td>{apikey.last_usage instanceof Date ? apikey.last_usage.toLocaleString() : String(apikey.last_usage || "")}</td> <td> <a href={`/Admin/APIKEY/edit/${apikey.id}`} className="btn btn-primary"> Edit Loading @@ -182,9 +190,9 @@ export default function ApiKeyListClient({ data }: { data: any }) { > <i className="bi bi-trash"></i> </button> <a href="/Admin/APIKEY/edit/new" className="btn btn-primary" style={{ borderRadius: "50%", width: 56, height: 56, fontSize: 28 }} title="Add"> <Link href="/Admin/APIKEY/edit/new" className="btn btn-primary" style={{ borderRadius: "50%", width: 56, height: 56, fontSize: 28 }} title="Add"> <i className="bi bi-plus"></i> </a> </Link> </div> {/* Delete Confirmation Modal */} <div className={`modal fade${showDeleteModal ? ' show d-block' : ''}`} tabIndex={-1} role="dialog" style={{ background: showDeleteModal ? 'rgba(0,0,0,0.5)' : undefined }}> Loading src/app/Admin/APIKEY/edit/[id]/ApiKeyEditPageClient.tsx +11 −9 Original line number Diff line number Diff line Loading @@ -4,8 +4,9 @@ import { useRouter } from "next/navigation"; import Link from "next/link"; import { saveAPIKey, saveNewAPIKey } from "./actions"; import "./ApiKeyEditPageClient.css"; import { ClientApiKeyEditProps } from "@/types/CustomTypes"; export default function ApiKeyEditPageClient({ data }: { data: { id: number, api_key: string, is_valid: boolean, label: string, last_usage: Date | null, valid_until: Date } }) { export default function ApiKeyEditPageClient({ data }: ClientApiKeyEditProps) { const router = useRouter(); Loading Loading @@ -37,8 +38,6 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api const { id, api_key } = await saveNewAPIKey(label, valid_until, is_valid); setNewAPIKEY(api_key); setApiKeyID(id); /*setTimeout(() => router.push(`/Admin/User/edit/${id}`), 1000);*/ } else { await saveAPIKey(ApiKeyID, label, valid_until, is_valid); Loading @@ -51,9 +50,12 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api } } setSuccess(true); //setTimeout(() => router.push("/Admin/Language"), 1000); } catch (err: any) { setError(err.message || "Failed to update Api Key"); } catch (err: unknown) { if (err instanceof Error) { setError((err as { message: string }).message); } else { setError("Failed to update Api Key"); } } finally { setLoading(false); } Loading Loading @@ -130,7 +132,7 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api id="valid_until" value={valid_until ? new Date(valid_until).toISOString().split('T')[0] : ""} required /* @ts-ignore */ // @ts-expect-error valid_until can be string or Date, conversion is handled here onChange={e => setValidUntil(e.target.value ? new Date(e.target.value) : "")} /> Loading @@ -154,7 +156,7 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api title="Copy API Key" onClick={() => { navigator.clipboard.writeText(NewAPIKEY); let tooltip = document.getElementById("myTooltip"); const tooltip = document.getElementById("myTooltip"); if (tooltip) { tooltip.innerHTML = "Copied"; setTimeout(() => { Loading @@ -172,7 +174,7 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api </div> <br /> Please save it, you won't be able to see it again. Please save it, you won't be able to see it again. </div> )} </form> Loading src/app/Admin/APIKEY/edit/[id]/page.tsx +2 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,8 @@ import { cookies } from "next/headers"; import { RefreshToken } from "@/components/refreshToken"; import { redirect } from "next/navigation"; export default async function APIKeyEditPageServer(props: { params: { id: string | number } }) { export default async function APIKeyEditPageServer(props: { params: Promise<{ id: string | number }> }) { const { params } = props; const apiKeyId = (await params).id; Loading src/app/Admin/APIKEY/page.tsx +3 −3 Original line number Diff line number Diff line import { RefreshToken } from "@/components/refreshToken"; import ApiKeyUserListClient from "./ApiKeyListClient"; import ApiKeyListClient from "./ApiKeyListClient"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; export default async function UserListServer() { export default async function ApiKeyListServer() { const cookieStore = cookies(); const token = (await cookieStore).get("access_token")?.value; const res = await fetch(`${process.env.API_URL}/apikeys/full`, { Loading @@ -26,7 +26,7 @@ export default async function UserListServer() { return ( <> <RefreshToken /> <ApiKeyUserListClient data={data} /> <ApiKeyListClient data={data} /> </> ); } Loading Loading
next.config.ts +5 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,11 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ experimental: { serverActions: { bodySizeLimit: "2mb", }, }, }; export default nextConfig;
src/app/Admin/APIKEY/ApiKeyListClient.tsx +22 −14 Original line number Diff line number Diff line 'use client'; import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState, useMemo } from "react"; import { deleteApiKey, saveEnabledApiKey } from "./actions"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { ClientApiKeyListProps, ApiKey } from "@/types/CustomTypes"; export default function ApiKeyListClient({ data }: { data: any }) { export default function ApiKeyListClient({ data }: ClientApiKeyListProps) { const router = useRouter(); const ApiKeys = Array.isArray(data?.apikeys) ? data.apikeys : []; const ApiKeys: ApiKey[] = useMemo(() => Array.isArray(data?.apikeys) ? data.apikeys : [], [data]); const [selectedApiKeys, setselectedApiKeys] = useState<Record<number, boolean>>({}); const handleSelect = (id: number, checked: boolean) => { Loading @@ -15,7 +18,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { const [enabledStates, setEnabledStates] = useState<Record<number, boolean>>(() => { const state: Record<number, boolean> = {}; ApiKeys.forEach((ApiKey: any) => { ApiKeys.forEach((ApiKey) => { state[ApiKey.id] = !!ApiKey.is_valid; }); return state; Loading @@ -26,7 +29,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { useEffect(() => { if (lastToggled.current) { const toggledId = lastToggled.current.id; const apiKeysExists = ApiKeys.some((ApiKey: any) => ApiKey.id === toggledId); const apiKeysExists = ApiKeys.some((ApiKey) => ApiKey.id === toggledId); if (!apiKeysExists) { setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: `Api Key with id ${toggledId} not found.`, type: 'danger' }]); lastToggled.current = null; Loading @@ -36,14 +39,19 @@ export default function ApiKeyListClient({ data }: { data: any }) { try { await saveEnabledApiKey(toggledId, lastToggled.current!.value); setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: `Api Key ${toggledId} updated successfully.`, type: 'success' }]); } catch (err: any) { setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: err.message || `Failed to update api key ${toggledId}.`, type: 'danger' }]); } catch (error: unknown) { let msg = `Failed to update api key ${toggledId}.`; if (error instanceof Error) { msg = (error as { message: string }).message; } setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: msg, type: 'danger' }]); } finally { lastToggled.current = null; } })(); } }, [enabledStates]); }, [enabledStates, ApiKeys]); const handleToggle = (id: number) => { setEnabledStates((prev) => { Loading Loading @@ -72,7 +80,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { setselectedApiKeys({}); router.refresh(); } catch (err) { } catch { setToasts(ts => [...ts, { id: Date.now() + Math.random(), message: 'Failed to delete selected languages.', type: 'danger' }]); setselectedApiKeys({}); } Loading Loading @@ -132,7 +140,7 @@ export default function ApiKeyListClient({ data }: { data: any }) { </tr> </thead> <tbody> {ApiKeys && ApiKeys.map((apikey: any) => ( {ApiKeys && ApiKeys.map((apikey) => ( <tr key={apikey.id}> <td> <input Loading Loading @@ -160,8 +168,8 @@ export default function ApiKeyListClient({ data }: { data: any }) { </div> </td> <td>{apikey.valid_until}</td> <td>{apikey.last_usage}</td> <td>{apikey.valid_until instanceof Date ? apikey.valid_until.toLocaleString() : String(apikey.valid_until || "")}</td> <td>{apikey.last_usage instanceof Date ? apikey.last_usage.toLocaleString() : String(apikey.last_usage || "")}</td> <td> <a href={`/Admin/APIKEY/edit/${apikey.id}`} className="btn btn-primary"> Edit Loading @@ -182,9 +190,9 @@ export default function ApiKeyListClient({ data }: { data: any }) { > <i className="bi bi-trash"></i> </button> <a href="/Admin/APIKEY/edit/new" className="btn btn-primary" style={{ borderRadius: "50%", width: 56, height: 56, fontSize: 28 }} title="Add"> <Link href="/Admin/APIKEY/edit/new" className="btn btn-primary" style={{ borderRadius: "50%", width: 56, height: 56, fontSize: 28 }} title="Add"> <i className="bi bi-plus"></i> </a> </Link> </div> {/* Delete Confirmation Modal */} <div className={`modal fade${showDeleteModal ? ' show d-block' : ''}`} tabIndex={-1} role="dialog" style={{ background: showDeleteModal ? 'rgba(0,0,0,0.5)' : undefined }}> Loading
src/app/Admin/APIKEY/edit/[id]/ApiKeyEditPageClient.tsx +11 −9 Original line number Diff line number Diff line Loading @@ -4,8 +4,9 @@ import { useRouter } from "next/navigation"; import Link from "next/link"; import { saveAPIKey, saveNewAPIKey } from "./actions"; import "./ApiKeyEditPageClient.css"; import { ClientApiKeyEditProps } from "@/types/CustomTypes"; export default function ApiKeyEditPageClient({ data }: { data: { id: number, api_key: string, is_valid: boolean, label: string, last_usage: Date | null, valid_until: Date } }) { export default function ApiKeyEditPageClient({ data }: ClientApiKeyEditProps) { const router = useRouter(); Loading Loading @@ -37,8 +38,6 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api const { id, api_key } = await saveNewAPIKey(label, valid_until, is_valid); setNewAPIKEY(api_key); setApiKeyID(id); /*setTimeout(() => router.push(`/Admin/User/edit/${id}`), 1000);*/ } else { await saveAPIKey(ApiKeyID, label, valid_until, is_valid); Loading @@ -51,9 +50,12 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api } } setSuccess(true); //setTimeout(() => router.push("/Admin/Language"), 1000); } catch (err: any) { setError(err.message || "Failed to update Api Key"); } catch (err: unknown) { if (err instanceof Error) { setError((err as { message: string }).message); } else { setError("Failed to update Api Key"); } } finally { setLoading(false); } Loading Loading @@ -130,7 +132,7 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api id="valid_until" value={valid_until ? new Date(valid_until).toISOString().split('T')[0] : ""} required /* @ts-ignore */ // @ts-expect-error valid_until can be string or Date, conversion is handled here onChange={e => setValidUntil(e.target.value ? new Date(e.target.value) : "")} /> Loading @@ -154,7 +156,7 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api title="Copy API Key" onClick={() => { navigator.clipboard.writeText(NewAPIKEY); let tooltip = document.getElementById("myTooltip"); const tooltip = document.getElementById("myTooltip"); if (tooltip) { tooltip.innerHTML = "Copied"; setTimeout(() => { Loading @@ -172,7 +174,7 @@ export default function ApiKeyEditPageClient({ data }: { data: { id: number, api </div> <br /> Please save it, you won't be able to see it again. Please save it, you won't be able to see it again. </div> )} </form> Loading
src/app/Admin/APIKEY/edit/[id]/page.tsx +2 −1 Original line number Diff line number Diff line Loading @@ -4,7 +4,8 @@ import { cookies } from "next/headers"; import { RefreshToken } from "@/components/refreshToken"; import { redirect } from "next/navigation"; export default async function APIKeyEditPageServer(props: { params: { id: string | number } }) { export default async function APIKeyEditPageServer(props: { params: Promise<{ id: string | number }> }) { const { params } = props; const apiKeyId = (await params).id; Loading
src/app/Admin/APIKEY/page.tsx +3 −3 Original line number Diff line number Diff line import { RefreshToken } from "@/components/refreshToken"; import ApiKeyUserListClient from "./ApiKeyListClient"; import ApiKeyListClient from "./ApiKeyListClient"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; export default async function UserListServer() { export default async function ApiKeyListServer() { const cookieStore = cookies(); const token = (await cookieStore).get("access_token")?.value; const res = await fetch(`${process.env.API_URL}/apikeys/full`, { Loading @@ -26,7 +26,7 @@ export default async function UserListServer() { return ( <> <RefreshToken /> <ApiKeyUserListClient data={data} /> <ApiKeyListClient data={data} /> </> ); } Loading