feat: filter regions
This commit is contained in:
15
src/components/button-filter.tsx
Normal file
15
src/components/button-filter.tsx
Normal 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>
|
||||||
|
}
|
@ -1,17 +1,30 @@
|
|||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { LNVpsApi, VmTemplateResponse } from "../api";
|
import { LNVpsApi, VmHostRegion, VmTemplateResponse } from "../api";
|
||||||
import VpsCard from "../components/vps-card";
|
import VpsCard from "../components/vps-card";
|
||||||
import { ApiUrl, NostrProfile } from "../const";
|
import { ApiUrl, NostrProfile } from "../const";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { VpsCustomOrder } from "../components/vps-custom";
|
import { VpsCustomOrder } from "../components/vps-custom";
|
||||||
import { LatestNews } from "../components/latest-news";
|
import { LatestNews } from "../components/latest-news";
|
||||||
|
import { FilterButton } from "../components/button-filter";
|
||||||
|
import { dedupe } from "@snort/shared";
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
const [offers, setOffers] = useState<VmTemplateResponse>();
|
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(() => {
|
useEffect(() => {
|
||||||
const api = new LNVpsApi(ApiUrl, undefined);
|
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 (
|
return (
|
||||||
@ -23,8 +36,24 @@ export default function HomePage() {
|
|||||||
Virtual Private Server hosting with flexible plans, high uptime, and
|
Virtual Private Server hosting with flexible plans, high uptime, and
|
||||||
dedicated support, tailored to your needs.
|
dedicated support, tailored to your needs.
|
||||||
</div>
|
</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">
|
<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 && (
|
{offers?.templates !== undefined && offers.templates.length === 0 && (
|
||||||
<div className="text-red-500 bold text-xl uppercase">
|
<div className="text-red-500 bold text-xl uppercase">
|
||||||
No offers available
|
No offers available
|
||||||
|
Reference in New Issue
Block a user