integratedhub/islands/TenantMessagesFilters.tsx
2026-02-14 02:20:19 +00:00

121 lines
3.9 KiB
TypeScript

interface TenantMessagesFiltersProps {
status: string;
sort: string;
search: string;
}
function updateQuery(updates: Record<string, string | null>) {
const url = new URL(globalThis.location.href);
for (const [key, value] of Object.entries(updates)) {
if (!value) {
url.searchParams.delete(key);
} else {
url.searchParams.set(key, value);
}
}
url.searchParams.set("page", "1");
globalThis.location.href = url.pathname + url.search;
}
export default function TenantMessagesFilters(
{ status, sort, search }: TenantMessagesFiltersProps,
) {
const handleStatusClick = (value: string) => (e: Event) => {
e.preventDefault();
updateQuery({ status: value === "all" ? null : value });
};
const handleSortChange = (e: Event) => {
const target = e.target as HTMLSelectElement;
updateQuery({ sort: target.value });
};
const handleSearchSubmit = (e: Event) => {
e.preventDefault();
const form = e.target as HTMLFormElement;
const formData = new FormData(form);
const query = (formData.get("q") || "").toString().trim();
updateQuery({ q: query.length > 0 ? query : null });
};
const buttonClass = (isActive: boolean) =>
`px-3 py-1 text-sm rounded-full transition-colors ${
isActive
? "bg-blue-600 text-white"
: "bg-gray-200 text-gray-700 hover:bg-gray-300"
}`;
return (
<div class="p-4 border-b border-gray-200 flex flex-col sm:flex-row sm:items-center justify-between space-y-3 sm:space-y-0">
<div class="flex flex-wrap gap-2">
<button
type="button"
onClick={handleStatusClick("all")}
aria-pressed={status === "all"}
class={buttonClass(status === "all")}
>
All
</button>
<button
type="button"
onClick={handleStatusClick("unread")}
aria-pressed={status === "unread"}
class={buttonClass(status === "unread")}
>
Unread
</button>
<button
type="button"
onClick={handleStatusClick("read")}
aria-pressed={status === "read"}
class={buttonClass(status === "read")}
>
Read
</button>
</div>
<form onSubmit={handleSearchSubmit} class="flex-grow max-w-md">
<div class="relative">
<input
type="search"
name="q"
defaultValue={search}
placeholder="Search messages..."
aria-label="Search messages"
class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm"
/>
<button type="submit" class="sr-only">Search</button>
<div class="absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none">
<svg
class="h-5 w-5 text-gray-400"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
>
<path
fill-rule="evenodd"
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
clip-rule="evenodd"
/>
</svg>
</div>
</div>
</form>
<div class="flex items-center space-x-3">
<span class="text-sm text-gray-500">Sort:</span>
<div class="w-32">
<select
onChange={handleSortChange}
defaultValue={sort}
class="block w-full pl-3 pr-10 py-2 text-base border-gray-300 focus:outline-none focus:ring-blue-500 focus:border-blue-500 sm:text-sm rounded-md"
>
<option value="newest">Newest First</option>
<option value="oldest">Oldest First</option>
</select>
</div>
</div>
</div>
);
}