BIG UPDATE: changed logic so only 1 network req is needed to get all scripts.

This commit is contained in:
Bram Suurd
2024-05-21 17:31:34 +02:00
parent fd1b3794b3
commit a323e9bcff
6 changed files with 95 additions and 80 deletions

View File

@@ -1,24 +1,59 @@
'use client'
import ScriptItem from "@/components/Script";
import ScriptBrowser from "@/components/ScriptBrowser";
import Particles from "@/components/ui/particles";
import { pb } from "@/lib/pocketbase";
import { Category } from "@/lib/types";
import { useEffect, useState } from "react";
export default function Page() {
const [links, setLinks] = useState<Category[]>([]);
const [isLoading , setIsLoading] = useState(true)
const fetchLinks = async () => {
try {
setIsLoading(true)
const res = await pb.collection("categories").getFullList({
expand: "items",
sort: "order",
requestKey: "desktop",
});
setLinks(res as unknown as Category[]);
setIsLoading(false)
} catch (error) {
console.error("Error fetching links:", error);
setIsLoading(false)
}
};
useEffect(() => {
fetchLinks();
}, []);
return (
<>
<Particles
className="animate-fade-in absolute inset-0 -z-10"
quantity={100}
/>
<div className="min-h-screen mb-3">
<div className="mt-20 flex sm:px-7 xl:px-0">
<div className="hidden sm:flex">
<ScriptBrowser />
{!isLoading ? (
<>
<Particles
className="animate-fade-in absolute inset-0 -z-10"
quantity={100}
/>
<div className="min-h-screen mb-3">
<div className="mt-20 flex sm:px-7 xl:px-0">
<div className="hidden sm:flex">
<ScriptBrowser items={links} />
</div>
<div className="mx-7 w-full sm:mx-0 sm:ml-7">
<ScriptItem items={links} />
</div>
</div>
<div className="mx-7 w-full sm:mx-0 sm:ml-7">
<ScriptItem />
</div>
</>
) : (
<div className="flex justify-center items-center h-screen">
<div className="animate-pulse"></div>
</div>
</div>
</div>
)}
</>
);
}

View File

@@ -8,27 +8,24 @@ import {
} from "@/components/ui/card";
import { pb } from "@/lib/pocketbase";
import { useEffect, useState } from "react";
import { Script } from "@/lib/types";
import { Category, Script } from "@/lib/types";
import Link from "next/link";
import Image from "next/image";
import { Button } from "./ui/button";
import { extractDate } from "@/lib/time";
function LatestScripts() {
function LatestScripts({items } : {items: Category[]}) {
const [latestScripts, setLatestScripts] = useState<Script[]>([]);
async function getLatestScripts() {
const res = await pb.collection("proxmox_scripts").getList(1, 3, {
sort: "-created",
requestKey: "latest_scripts",
});
setLatestScripts(res.items as unknown as Script[]);
}
useEffect(() => {
getLatestScripts();
}, []);
if (items) {
const scripts = items.flatMap((category) => category.expand.items);
const sortedScripts = scripts.sort((a, b) => {
return new Date(b.created).getTime() - new Date(a.created).getTime();
});
setLatestScripts(sortedScripts.slice(0, 3));
}
}, [items]);
return (
<div className="">

View File

@@ -8,32 +8,25 @@ import {
} from "@/components/ui/card";
import { pb } from "@/lib/pocketbase";
import { useEffect, useState } from "react";
import { Script } from "@/lib/types";
import { Category, Script } from "@/lib/types";
import Link from "next/link";
import Image from "next/image";
import { Button } from "./ui/button";
import { extractDate } from "@/lib/time";
export default function MostViewedScripts() {
export default function MostViewedScripts({items} : {items: Category[]}) {
const [latestScripts, setLatestScripts] = useState<Script[]>([]);
async function getLatestScripts() {
try {
const res = await pb.collection("proxmox_scripts").getList(1, 3, {
sort: "mostViewedPosition",
filter: "isMostViewed = true",
});
setLatestScripts(res.items as unknown as Script[]);
} catch (error) {
console.error("Error fetching scripts:", error);
}
}
useEffect(() => {
getLatestScripts();
}, []);
if (items) {
const scripts = items.flatMap((category) => category.expand.items);
const mostViewedScripts = scripts.filter((item) => item.isMostViewed);
const sortedScripts = mostViewedScripts.sort((a, b) => {
return a.mostViewedPosition - b.mostViewedPosition;
});
setLatestScripts(sortedScripts.slice(0, 3));
}
}, [items]);
return (
<div className="">

View File

@@ -8,28 +8,25 @@ import { toast } from "sonner";
import { Clipboard, Info, X } from "lucide-react";
import { Separator } from "@/components/ui/separator";
import Link from "next/link";
import { Script } from "@/lib/types";
import { useSearchParams } from "next/navigation";
import { Category, Script } from "@/lib/types";
import { useSearchParams } from "next/navigation";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import LatestScripts from "./LatestScripts";
import MostViewedScripts from "./MostViewedScripts";
function ScriptItem() {
function ScriptItem({ items }: { items: Category[] }) {
const [item, setItem] = useState<Script | null>(null);
const id = useSearchParams().get("id");
const getItem = async () => {
const res = await pb.collection('proxmox_scripts').getFirstListItem(`title="${id}"`);
setItem(res as unknown as Script);
};
useEffect(() => {
if (id) {
getItem();
} else {
setItem(null);
if (items) {
const script = items
.map((category) => category.expand.items)
.flat()
.find((script) => script.title === id);
setItem(script || null);
}
}, [id]);
}, [id, items]);
function handleCopy(type: string, value: any) {
navigator.clipboard.writeText(value);
@@ -42,7 +39,13 @@ function ScriptItem() {
amountOfScriptsCopied = (parseInt(amountOfScriptsCopied) + 1).toString();
localStorage.setItem("amountOfScriptsCopied", amountOfScriptsCopied);
if (parseInt(amountOfScriptsCopied) === 3 || parseInt(amountOfScriptsCopied) === 10 || parseInt(amountOfScriptsCopied) === 25 || parseInt(amountOfScriptsCopied) === 50 || parseInt(amountOfScriptsCopied) === 100) {
if (
parseInt(amountOfScriptsCopied) === 3 ||
parseInt(amountOfScriptsCopied) === 10 ||
parseInt(amountOfScriptsCopied) === 25 ||
parseInt(amountOfScriptsCopied) === 50 ||
parseInt(amountOfScriptsCopied) === 100
) {
setTimeout(() => {
toast.info(
<div className="flex flex-col gap-3">
@@ -76,7 +79,6 @@ function ScriptItem() {
);
}
function closeScript() {
// remove the id from the url and reset the state
window.history.pushState({}, document.title, window.location.pathname);
@@ -384,8 +386,8 @@ function ScriptItem() {
)}
{item ? null : (
<div className="flex w-full flex-col gap-5">
<LatestScripts />
<MostViewedScripts />
<LatestScripts items={items} />
<MostViewedScripts items={items} />
</div>
)}
</Suspense>

View File

@@ -9,15 +9,20 @@ import { Input } from "@/components/ui/input";
import Link from "next/link";
import React, { useState, useEffect, useRef, useMemo } from "react";
import { Category } from "@/lib/types";
import { pb } from "@/lib/pocketbase";
import { Badge } from "./ui/badge";
import clsx from "clsx";
const ScriptBrowser = () => {
const ScriptBrowser = ({ items }: { items: Category[] }) => {
const [links, setLinks] = useState<Category[]>([]);
const [searchTerm, setSearchTerm] = useState("");
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
if (items) {
setLinks(items);
}
}, [items]);
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "/") {
@@ -32,24 +37,6 @@ const ScriptBrowser = () => {
};
}, []);
const fetchLinks = async () => {
try {
// you can also fetch all records at once via getFullList
const res = await pb.collection("categories").getFullList({
expand: "items",
sort: "order",
requestKey: "desktop",
});
setLinks(res as unknown as Category[]);
} catch (error) {
console.error("Error fetching links:", error);
}
};
useEffect(() => {
fetchLinks();
}, []);
const handleSearch = (value: string) => {
setSearchTerm(value);
};

View File

@@ -30,6 +30,7 @@ export type Script = {
updated: string;
website: string;
isMostViewed: boolean;
mostViewedPosition: number;
};
export interface Category {