feat(PROJ-9): implement labels frontend - LabelList, LabelPicker, search integration, admin UI
This commit is contained in:
+24
-1
@@ -5,6 +5,7 @@ import { useRouter } from "next/navigation";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
import { searchEmails, exportMailsZIP, uploadMailFilesUser, getUploadProgressUser, type SearchHit, type UploadJob } from "@/lib/api";
|
||||
import { Navbar } from "@/components/navbar";
|
||||
import { LabelList } from "@/components/LabelList";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
@@ -56,6 +57,7 @@ export default function SearchPage() {
|
||||
const [dateTo, setDateTo] = useState("");
|
||||
const [sort, setSort] = useState("date_desc");
|
||||
const [hasAttachment, setHasAttachment] = useState<boolean | undefined>(undefined);
|
||||
const [selectedLabelId, setSelectedLabelId] = useState<number | null>(null);
|
||||
|
||||
const [results, setResults] = useState<SearchHit[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
@@ -94,6 +96,7 @@ export default function SearchPage() {
|
||||
date_to: dateTo || undefined,
|
||||
sort: sort !== "date_desc" ? sort : undefined,
|
||||
has_attachment: hasAttachment,
|
||||
label_id: selectedLabelId ?? undefined,
|
||||
page: p,
|
||||
page_size: PAGE_SIZE,
|
||||
});
|
||||
@@ -108,7 +111,7 @@ export default function SearchPage() {
|
||||
setSearching(false);
|
||||
}
|
||||
},
|
||||
[query, fromFilter, toFilter, dateFrom, dateTo, sort, hasAttachment]
|
||||
[query, fromFilter, toFilter, dateFrom, dateTo, sort, hasAttachment, selectedLabelId]
|
||||
);
|
||||
|
||||
// Alle Mails beim Öffnen der Seite laden — direkt, ohne useCallback-Closure
|
||||
@@ -129,6 +132,13 @@ export default function SearchPage() {
|
||||
.finally(() => setSearching(false));
|
||||
}, [user]);
|
||||
|
||||
// Re-search when label selection changes
|
||||
useEffect(() => {
|
||||
if (!user || !searched) return;
|
||||
doSearch(1);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedLabelId]);
|
||||
|
||||
function handleSubmit(e: React.FormEvent) {
|
||||
e.preventDefault();
|
||||
doSearch(1);
|
||||
@@ -216,6 +226,17 @@ export default function SearchPage() {
|
||||
</div>
|
||||
)}
|
||||
{!authLoading && user && (<>
|
||||
<div className="flex gap-6">
|
||||
{/* Label sidebar */}
|
||||
<div className="hidden md:block w-48 shrink-0">
|
||||
<LabelList
|
||||
selectedLabelId={selectedLabelId}
|
||||
onLabelSelect={setSelectedLabelId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Main content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
@@ -439,6 +460,8 @@ export default function SearchPage() {
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>{/* end flex-1 */}
|
||||
</div>{/* end flex gap-6 */}
|
||||
|
||||
<Dialog open={exportOpen} onOpenChange={setExportOpen}>
|
||||
<DialogContent>
|
||||
|
||||
Reference in New Issue
Block a user