feat: filter regions

This commit is contained in:
2025-03-24 16:10:42 +00:00
parent c0b7836ce3
commit 3c3218044b
2 changed files with 47 additions and 3 deletions

View File

@ -0,0 +1,15 @@
import classNames from "classnames";
import { ReactNode } from "react";
export function FilterButton({ children, onClick, active }: { children: ReactNode, onClick?: () => Promise<void> | void, active?: boolean }) {
return <div
className={classNames("rounded-full outline outline-1 px-4 py-1 cursor-pointer select-none",
{
"bg-neutral-800 outline-neutral-300": active,
"bg-neutral-900 outline-neutral-800 text-neutral-500": !active
}
)}
onClick={onClick}>
{children}
</div>
}

View File

@ -1,17 +1,30 @@
import { useState, useEffect } from "react";
import { LNVpsApi, VmTemplateResponse } from "../api";
import { LNVpsApi, VmHostRegion, VmTemplateResponse } from "../api";
import VpsCard from "../components/vps-card";
import { ApiUrl, NostrProfile } from "../const";
import { Link } from "react-router-dom";
import { VpsCustomOrder } from "../components/vps-custom";
import { LatestNews } from "../components/latest-news";
import { FilterButton } from "../components/button-filter";
import { dedupe } from "@snort/shared";
export default function HomePage() {
const [offers, setOffers] = useState<VmTemplateResponse>();
const [region, setRegion] = useState<Array<number>>([]);
const regions = (offers?.templates.map((t) => t.region) ?? []).reduce((acc, v) => {
if (acc[v.id] === undefined) {
acc[v.id] = v;
}
return acc;
}, {} as Record<number, VmHostRegion>);
useEffect(() => {
const api = new LNVpsApi(ApiUrl, undefined);
api.listOffers().then((o) => setOffers(o));
api.listOffers().then((o) => {
setOffers(o)
setRegion(dedupe(o.templates.map((z) => z.region.id)));
});
}, []);
return (
@ -23,8 +36,24 @@ export default function HomePage() {
Virtual Private Server hosting with flexible plans, high uptime, and
dedicated support, tailored to your needs.
</div>
{Object.keys(regions).length > 1 && <div className="flex gap-2 items-center">
Regions:
{Object.values(regions).map((r) => {
return <FilterButton
active={region.includes(r.id)}
onClick={() => setRegion(x => {
if (x.includes(r.id)) {
return x.filter(y => y != r.id);
} else {
return [...x, r.id];
}
})}>
{r.name}
</FilterButton>;
})}
</div>}
<div className="grid grid-cols-3 gap-2">
{offers?.templates.map((a) => <VpsCard spec={a} key={a.id} />)}
{offers?.templates.filter((t) => region.includes(t.region.id)).sort((a, b) => a.cost_plan.amount - b.cost_plan.amount).map((a) => <VpsCard spec={a} key={a.id} />)}
{offers?.templates !== undefined && offers.templates.length === 0 && (
<div className="text-red-500 bold text-xl uppercase">
No offers available