add pagenation for domain list
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
} from "@/components/ui/card";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Modal } from "@/components/ui/modal";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
@@ -88,7 +89,7 @@ export default function DomainList({ user, action }: DomainListProps) {
|
||||
total: number;
|
||||
list: DomainFormData[];
|
||||
}>(
|
||||
`${action}?page=${currentPage}&size=${pageSize}&slug=${searchParams.slug}&userName=${searchParams.userName}&target=${searchParams.target}`,
|
||||
`${action}?page=${currentPage}&size=${pageSize}&target=${searchParams.target}`,
|
||||
fetcher,
|
||||
);
|
||||
|
||||
@@ -129,10 +130,14 @@ export default function DomainList({ user, action }: DomainListProps) {
|
||||
<>
|
||||
<Card className="xl:col-span-2">
|
||||
<CardHeader className="flex flex-row items-center">
|
||||
<CardDescription className="text-balance text-lg font-bold">
|
||||
<div className="flex items-center gap-1 text-balance text-lg font-bold">
|
||||
<span>Total Domains:</span>{" "}
|
||||
<span className="font-bold">{data && data.total}</span>
|
||||
</CardDescription>
|
||||
{isLoading ? (
|
||||
<Skeleton className="h-6 w-16" />
|
||||
) : (
|
||||
<span className="font-bold">{data && data.total}</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="ml-auto flex items-center justify-end gap-3">
|
||||
<Button
|
||||
@@ -161,30 +166,32 @@ export default function DomainList({ user, action }: DomainListProps) {
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
{/* <div className="mb-2 flex-row items-center gap-2 space-y-2 sm:flex sm:space-y-0">
|
||||
<div className="mb-2 flex-row items-center gap-2 space-y-2 sm:flex sm:space-y-0">
|
||||
<div className="relative w-full">
|
||||
<Input
|
||||
className="h-8 text-xs md:text-xs"
|
||||
placeholder="Search by slug..."
|
||||
value={searchParams.slug}
|
||||
placeholder="Search by domain name..."
|
||||
value={searchParams.target}
|
||||
onChange={(e) => {
|
||||
setSearchParams({
|
||||
...searchParams,
|
||||
slug: e.target.value,
|
||||
target: e.target.value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{searchParams.slug && (
|
||||
{searchParams.target && (
|
||||
<Button
|
||||
className="absolute right-2 top-1/2 h-6 -translate-y-1/2 rounded-full px-1 text-gray-500 hover:text-gray-700"
|
||||
onClick={() => setSearchParams({ ...searchParams, slug: "" })}
|
||||
onClick={() =>
|
||||
setSearchParams({ ...searchParams, target: "" })
|
||||
}
|
||||
variant={"ghost"}
|
||||
>
|
||||
<Icons.close className="size-3" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<TableHeader className="bg-gray-100/50 dark:bg-primary-foreground">
|
||||
|
||||
@@ -4,7 +4,6 @@ import {
|
||||
createDomain,
|
||||
deleteDomain,
|
||||
getAllDomains,
|
||||
invalidateDomainConfigCache,
|
||||
updateDomain,
|
||||
} from "@/lib/dto/domains";
|
||||
import { checkUserStatus } from "@/lib/dto/user";
|
||||
@@ -19,13 +18,18 @@ export async function GET(req: NextRequest) {
|
||||
return Response.json("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
// TODO: Add pagination
|
||||
const domains = await getAllDomains();
|
||||
const url = new URL(req.url);
|
||||
const page = url.searchParams.get("page");
|
||||
const size = url.searchParams.get("size");
|
||||
const target = url.searchParams.get("target") || "";
|
||||
|
||||
return Response.json(
|
||||
{ list: domains, total: domains.length },
|
||||
{ status: 200 },
|
||||
const data = await getAllDomains(
|
||||
Number(page || "1"),
|
||||
Number(size || "10"),
|
||||
target,
|
||||
);
|
||||
|
||||
return Response.json(data, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error("[Error]", error);
|
||||
return Response.json(error.message || "Server error", { status: 500 });
|
||||
@@ -61,8 +65,6 @@ export async function POST(req: NextRequest) {
|
||||
active: true,
|
||||
});
|
||||
|
||||
invalidateDomainConfigCache();
|
||||
|
||||
return Response.json(newDomain, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error("[Error]", error);
|
||||
@@ -112,8 +114,6 @@ export async function PUT(req: NextRequest) {
|
||||
max_dns_records,
|
||||
});
|
||||
|
||||
invalidateDomainConfigCache();
|
||||
|
||||
return Response.json(updatedDomain, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error("[Error]", error);
|
||||
@@ -137,8 +137,6 @@ export async function DELETE(req: NextRequest) {
|
||||
|
||||
const deletedDomain = await deleteDomain(domain_name);
|
||||
|
||||
invalidateDomainConfigCache();
|
||||
|
||||
return Response.json(deletedDomain, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error("[Error]", error);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getAllDomains, invalidateDomainConfigCache } from "@/lib/dto/domains";
|
||||
import { getAllDomains } from "@/lib/dto/domains";
|
||||
|
||||
export async function getDomainConfig() {
|
||||
return await getAllDomains();
|
||||
@@ -7,7 +7,7 @@ export async function getDomainConfig() {
|
||||
export async function getCloudflareCredentials(domain_name: string) {
|
||||
try {
|
||||
const domains = await getAllDomains();
|
||||
const domain = domains.find((d) => d.domain_name === domain_name);
|
||||
const domain = domains.list.find((d) => d.domain_name === domain_name);
|
||||
if (!domain || !domain.cf_api_key || !domain.cf_email) {
|
||||
throw new Error(
|
||||
`No Cloudflare credentials found for domain: ${domain_name}`,
|
||||
@@ -32,5 +32,3 @@ export async function getCloudflareCredentials(domain_name: string) {
|
||||
function decrypt(encryptedKey: string) {
|
||||
return encryptedKey; // Replace with actual decryption logic
|
||||
}
|
||||
|
||||
export { invalidateDomainConfigCache };
|
||||
|
||||
@@ -5,7 +5,7 @@ import { prisma } from "../db";
|
||||
// In-memory cache
|
||||
let domainConfigCache: Domain[] | null = null;
|
||||
let lastCacheUpdate = 0;
|
||||
const CACHE_DURATION = 60 * 1000; // Cache for 1 minute in memory
|
||||
const CACHE_DURATION = 60 * 1000;
|
||||
|
||||
export const FeatureMap = {
|
||||
short: "enable_short_link",
|
||||
@@ -34,20 +34,33 @@ export interface DomainFormData extends DomainConfig {
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export async function getAllDomains() {
|
||||
export async function getAllDomains(page = 1, size = 10, target: string = "") {
|
||||
try {
|
||||
const now = Date.now();
|
||||
if (domainConfigCache && now - lastCacheUpdate < CACHE_DURATION) {
|
||||
return domainConfigCache;
|
||||
let option: any;
|
||||
|
||||
if (target) {
|
||||
option = {
|
||||
domain_name: {
|
||||
contains: target,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const domains = await prisma.domain.findMany({
|
||||
// where: { active: true },
|
||||
});
|
||||
const [total, list] = await prisma.$transaction([
|
||||
prisma.domain.count({
|
||||
where: option,
|
||||
}),
|
||||
prisma.domain.findMany({
|
||||
where: option,
|
||||
skip: (page - 1) * size,
|
||||
take: size,
|
||||
orderBy: {
|
||||
updatedAt: "desc",
|
||||
},
|
||||
}),
|
||||
]);
|
||||
|
||||
domainConfigCache = domains;
|
||||
lastCacheUpdate = now;
|
||||
return domains;
|
||||
return { list, total };
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to fetch domain config: ${error.message}`);
|
||||
}
|
||||
@@ -58,11 +71,6 @@ export async function getDomainsByFeature(
|
||||
admin: boolean = false,
|
||||
) {
|
||||
try {
|
||||
const now = Date.now();
|
||||
if (domainConfigCache && now - lastCacheUpdate < CACHE_DURATION) {
|
||||
return domainConfigCache;
|
||||
}
|
||||
|
||||
const domains = await prisma.domain.findMany({
|
||||
where: { [feature]: true },
|
||||
select: {
|
||||
@@ -129,8 +137,3 @@ export async function deleteDomain(domain_name: string) {
|
||||
throw new Error(`Failed to delete domain`);
|
||||
}
|
||||
}
|
||||
|
||||
export function invalidateDomainConfigCache() {
|
||||
domainConfigCache = null;
|
||||
lastCacheUpdate = 0;
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user