Files
MikrotikManager/components/optimizer-homes-list.tsx

46 lines
3.3 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client"
import { useEffect, useMemo, type ReactNode } from "react"
import { useSearchParams } from "next/navigation"
import type { HomeEntry } from "@/lib/route-optimizer-data"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function OptimizerHomesList({ homes, children }: { homes: HomeEntry[]; children: (entry: HomeEntry) => ReactNode }) {
const params = useSearchParams()
const query = params.get("home_q") ?? ""
const rawPage = params.get("home_page") ?? "1"
const requestedPage = /^[1-9]\d*$/.test(rawPage) && Number.isSafeInteger(Number(rawPage)) ? Number(rawPage) - 1 : 0
const filtered = useMemo(() => {
const value = query.trim().toLowerCase()
return value ? homes.filter(({ home }) => `${home.label} ${home.id} ${home.ip} ${home.site} ${home.country}`.toLowerCase().includes(value)) : homes
}, [homes, query])
const pages = Math.max(1, Math.ceil(filtered.length / 5))
const page = Math.min(requestedPage, pages - 1)
function change(queryValue: string, pageValue: number, push = false) {
const url = new URL(window.location.href)
if (queryValue) url.searchParams.set("home_q", queryValue); else url.searchParams.delete("home_q")
if (pageValue) url.searchParams.set("home_page", String(pageValue + 1)); else url.searchParams.delete("home_page")
window.history[push ? "pushState" : "replaceState"](null, "", url.pathname + url.search + url.hash)
}
useEffect(() => {
if (requestedPage < pages) return
const url = new URL(window.location.href)
if (page) url.searchParams.set("home_page", String(page + 1)); else url.searchParams.delete("home_page")
window.history.replaceState(null, "", url.pathname + url.search + url.hash)
}, [requestedPage, pages, page])
const controlled = homes.length > 5 || !!query || requestedPage > 0
return <section aria-label="Домашние устройства оптимизатора" className="flex min-w-0 flex-col gap-4">
{controlled && <div className="rounded-xl border border-border bg-background p-4 flex min-w-0 flex-col gap-3">
<Input aria-label="Поиск домашних устройств оптимизатора" placeholder="Имя, IP или площадка…" value={query} onChange={event => change(event.target.value, 0)} />
<p role="status" className="text-xs text-muted-foreground">Показаны {filtered.length ? page * 5 + 1 : 0}–{Math.min((page + 1) * 5, filtered.length)} из {filtered.length} устройств. Всего {homes.length}.</p>
<div className="flex flex-wrap gap-2">
<Button type="button" variant="outline" className="min-h-11" disabled={!page} aria-label="Предыдущая страница домашних устройств" onClick={() => change(query, page - 1, true)}>Назад</Button>
<Button type="button" variant="outline" className="min-h-11" disabled={page >= pages - 1} aria-label="Следующая страница домашних устройств" onClick={() => change(query, page + 1, true)}>Далее</Button>
</div>
{!filtered.length && <p className="text-sm text-muted-foreground">Домашние устройства по запросу не найдены.</p>}
</div>}
{filtered.slice(page * 5, (page + 1) * 5).map(children)}
</section>
}