Files
lms-sb/src/components/admin/users-search.tsx
T
admins d0ba4bf909 Polish: homework filters, users search/popup, admin comments
Homework (/curator/homework):
- Search by student name/email
- Filter by status (pending/reviewed) and course
- Server-side pagination (20 per page) with URL params

Users (/admin/users):
- Search by name/email, filter by role
- Hover popup on each row: enrolled courses + expiry dates + email
- Pagination (20 per page) with URL params

Comments (/admin/comments):
- New admin page with all active comments
- Search by author or text content
- One-click delete (soft-delete) from the table
- Pagination (30 per page)
- Added "Комментарии" link to admin nav

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 13:00:57 +05:00

71 lines
2.5 KiB
TypeScript
Raw 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 { useRouter, usePathname } from "next/navigation";
import { useTransition } from "react";
import { Search } from "lucide-react";
const inputStyle: React.CSSProperties = {
border: "2px solid var(--border)",
background: "var(--background)",
outline: "none",
padding: "0.4rem 0.75rem",
fontSize: "0.8rem",
fontFamily: "inherit",
};
export function UsersSearch({ initialSearch, initialRole }: { initialSearch: string; initialRole: string }) {
const router = useRouter();
const pathname = usePathname();
const [, startTransition] = useTransition();
function update(search: string, role: string) {
const params = new URLSearchParams();
if (search) params.set("search", search);
if (role) params.set("role", role);
startTransition(() => router.push(`${pathname}?${params.toString()}`));
}
return (
<div className="flex flex-wrap gap-2 mb-4">
<div className="relative">
<Search size={13} className="absolute left-2.5 top-1/2 -translate-y-1/2" style={{ color: "var(--muted-foreground)" }} />
<input
defaultValue={initialSearch}
placeholder="Поиск по имени или email"
style={{ ...inputStyle, paddingLeft: "2rem", width: 240 }}
onFocus={(e) => (e.currentTarget.style.borderColor = "var(--foreground)")}
onBlur={(e) => {
e.currentTarget.style.borderColor = "var(--border)";
update(e.currentTarget.value.trim(), initialRole);
}}
onKeyDown={(e) => { if (e.key === "Enter") e.currentTarget.blur(); }}
/>
</div>
<select
defaultValue={initialRole}
onChange={(e) => update(initialSearch, e.target.value)}
style={{ ...inputStyle, appearance: "none", cursor: "pointer" }}
onFocus={(e) => (e.currentTarget.style.borderColor = "var(--foreground)")}
onBlur={(e) => (e.currentTarget.style.borderColor = "var(--border)")}
>
<option value="">Все роли</option>
<option value="student">Ученики</option>
<option value="curator">Кураторы</option>
<option value="admin">Администраторы</option>
</select>
{(initialSearch || initialRole) && (
<button
type="button"
onClick={() => startTransition(() => router.push(pathname))}
className="text-xs px-3"
style={{ border: "2px solid var(--border)", color: "var(--muted-foreground)" }}
>
Сбросить
</button>
)}
</div>
);
}