121 lines
3.9 KiB
TypeScript
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>
|
|
);
|
|
}
|