useSites Hook & Searchbar & Layout component

This commit is contained in:
headlesdev 2025-05-18 13:15:11 +02:00
parent 366ad21ed1
commit 20dc406fd1
3 changed files with 127 additions and 52 deletions

View File

@ -3,10 +3,9 @@ import Sidebar from "@/components/Sidebar";
import { Plus } from "lucide-react";
import AddSite from "@/components/dialogues/AddSite";
import Sites from "@/components/cards/Sites";
import axios from "axios";
import { useEffect, useState, useCallback } from "react";
import Pagination from "@/components/Pagination";
import Cookies from "js-cookie";
import useSites from "@/hooks/useSites";
import SearchAndLayout from "@/components/SearchAndLayout";
interface SitesPageProps {
username: string;
@ -14,40 +13,18 @@ interface SitesPageProps {
}
export default function SitesPage({ username, name }: SitesPageProps) {
const [sites, setSites] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [itemPerPage, setItemPerPage] = useState(5);
const [total, setTotal] = useState(0);
const [search, setSearch] = useState("");
const {
sites,
currentPage,
itemPerPage,
total,
search,
setSearch,
handlePageChange,
setItemPerPage,
loadSites
} = useSites();
const handlePageChange = (page: number) => {
setCurrentPage(page);
};
const loadSites = useCallback(() => {
axios.get('/api/sites/get_all', {
params: {
currentPage,
itemPerPage,
search,
},
}).then((response) => {
setSites(response.data.sites);
setTotal(response.data.total);
});
}, [currentPage, itemPerPage, search]);
useEffect(() => {
loadSites();
}, [loadSites]);
useEffect(() => {
const itemPerPage = Cookies.get('sites-itemPerPage');
if (itemPerPage) {
setItemPerPage(Number(itemPerPage));
}
}, []);
return (
<Sidebar
username={username}
@ -58,30 +35,41 @@ export default function SitesPage({ username, name }: SitesPageProps) {
<div className="flex gap-4 items-center">
<div className="flex-1">
<h1 className="text-2xl font-bold">Sites</h1>
<p className="text-sm opacity-70">Manage your sites. Sites are real-world locations where you can monitor your assets & add networks.</p>
<p className="text-sm opacity-70">
Manage your sites. Sites are real-world locations where you can
monitor your assets & add networks.
</p>
</div>
<button className="btn btn-primary" onClick={() => document.getElementById('add_site')?.showModal()}>
<button
className="btn btn-primary"
onClick={() => document.getElementById('add_site')?.showModal()}
>
<Plus className="w-5 h-5" />
Add Site
</button>
</div>
<AddSite onSiteAdded={loadSites} />
<SearchAndLayout
search={search}
setSearch={setSearch}
itemPerPage={itemPerPage}
setItemPerPage={setItemPerPage}
/>
<div className="flex gap-2 items-center pt-4">
<input type="text" placeholder="Search..." className="input input-bordered w-full" onChange={(e) => setSearch(e.target.value)} />
<select defaultValue="Pick a font" className="select w-24" value={itemPerPage} onChange={(e) => {
setItemPerPage(Number(e.target.value));
Cookies.set('sites-itemPerPage', e.target.value);
}}>
<option disabled={true}>Layout</option>
<option value={5}>List</option>
<option value={10}>Grid</option>
</select>
</div>
<div className={itemPerPage === 5 ? "flex flex-col gap-4 pt-4" : "grid grid-cols-1 md:grid-cols-2 gap-4 pt-4"}>
<div className={
itemPerPage === 5
? "flex flex-col gap-4 pt-4"
: "grid grid-cols-1 md:grid-cols-2 gap-4 pt-4"
}>
{sites.map((site: any) => (
<Sites key={site.id} id={site.id} name={site.name} description={site.description} networks={site.networks} />
<Sites
key={site.id}
id={site.id}
name={site.name}
description={site.description}
networks={site.networks}
/>
))}
</div>

View File

@ -0,0 +1,38 @@
import { ChangeEvent } from "react";
interface SearchAndLayoutProps {
search: string;
setSearch: (value: string) => void;
itemPerPage: number;
setItemPerPage: (value: number) => void;
}
const SearchAndLayout = ({
search,
setSearch,
itemPerPage,
setItemPerPage
}: SearchAndLayoutProps) => (
<div className="flex gap-2 items-center pt-4">
<input
type="text"
placeholder="Search..."
className="input input-bordered w-full"
value={search}
onChange={(e: ChangeEvent<HTMLInputElement>) => setSearch(e.target.value)}
/>
<select
className="select w-24"
value={itemPerPage}
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
setItemPerPage(Number(e.target.value))
}
>
<option disabled>Layout</option>
<option value={5}>List</option>
<option value={10}>Grid</option>
</select>
</div>
);
export default SearchAndLayout;

49
hooks/useSites.ts Normal file
View File

@ -0,0 +1,49 @@
import { useState, useEffect, useCallback } from "react";
import axios from "axios";
import Cookies from "js-cookie";
const useSites = () => {
const [sites, setSites] = useState([]);
const [currentPage, setCurrentPage] = useState(1);
const [itemPerPage, setItemPerPage] = useState(5);
const [total, setTotal] = useState(0);
const [search, setSearch] = useState("");
const loadSites = useCallback(() => {
axios.get('/api/sites/get_all', {
params: { currentPage, itemPerPage, search }
}).then((response) => {
setSites(response.data.sites);
setTotal(response.data.total);
});
}, [currentPage, itemPerPage, search]);
useEffect(() => {
loadSites();
}, [loadSites]);
useEffect(() => {
const savedItemPerPage = Cookies.get('sites-itemPerPage');
if (savedItemPerPage) setItemPerPage(Number(savedItemPerPage));
}, []);
useEffect(() => {
Cookies.set('sites-itemPerPage', itemPerPage.toString());
}, [itemPerPage]);
const handlePageChange = (page: number) => setCurrentPage(page);
return {
sites,
currentPage,
itemPerPage,
total,
search,
setSearch,
handlePageChange,
setItemPerPage,
loadSites
};
};
export default useSites;