fix: mail grouping collapsible groups, no sticky header, recursive subgroups with all mails

This commit is contained in:
Agent Zero
2026-07-30 18:03:48 +02:00
parent 61b9d2958e
commit 2f4f9803b9
+78 -27
View File
@@ -9,9 +9,10 @@ import { useTranslation } from 'react-i18next';
import type { Mail } from '@/api/mail';
import { decodeMimeHeader } from '@/api/mail';
import { EmptyState } from '@/components/ui/EmptyState';
import { Loader2, Paperclip, Star, ChevronDown } from 'lucide-react';
import { Loader2, Paperclip, Star, ChevronDown, ChevronRight } from 'lucide-react';
import { formatSmartDate } from '@/utils/date';
import type { GroupedMails } from '@/components/mail/MailGroupPanel';
import type { Mail } from '@/api/mail';
export interface MailListProps {
mails: Mail[];
@@ -30,6 +31,73 @@ function formatDate(dateStr: string): string {
return formatSmartDate(dateStr) || dateStr;
}
// Collapsible group section for grouped mail display
function GroupSection({
group,
level = 0,
selectedMailId,
selectedMailIds,
onSelectMail,
onToggleSelect,
renderMailItem,
}: {
group: GroupedMails;
level?: number;
selectedMailId: string | null;
selectedMailIds: Set<string>;
onSelectMail: (mail: Mail) => void;
onToggleSelect: (mailId: string) => void;
renderMailItem: (mail: Mail) => React.ReactNode;
}) {
const [collapsed, setCollapsed] = useState(false);
const hasSubGroups = group.subGroups && group.subGroups.length > 0;
// Count total mails including subGroups
const totalCount = hasSubGroups
? group.subGroups!.reduce((sum, sub) => sum + sub.mails.length, 0)
: group.mails.length;
return (
<li className="bg-secondary-50/30">
<div
className="flex items-center gap-2 px-3 py-2 bg-secondary-100/70 cursor-pointer hover:bg-secondary-100"
style={{ paddingLeft: `${level * 12 + 12}px` }}
onClick={() => setCollapsed(!collapsed)}
>
{collapsed ? (
<ChevronRight className="w-3.5 h-3.5 text-secondary-500 flex-shrink-0" />
) : (
<ChevronDown className="w-3.5 h-3.5 text-secondary-500 flex-shrink-0" />
)}
<span className="text-xs font-semibold text-secondary-700">{group.label}</span>
<span className="text-[10px] text-secondary-400">({totalCount})</span>
</div>
{!collapsed && (
<>
<ul className="divide-y divide-secondary-100">
{group.mails.map((mail) => renderMailItem(mail))}
</ul>
{hasSubGroups && (
<ul className="border-l border-secondary-200 ml-3">
{group.subGroups!.map((sub) => (
<GroupSection
key={sub.key}
group={sub}
level={level + 1}
selectedMailId={selectedMailId}
selectedMailIds={selectedMailIds}
onSelectMail={onSelectMail}
onToggleSelect={onToggleSelect}
renderMailItem={renderMailItem}
/>
))}
</ul>
)}
</>
)}
</li>
);
}
export function MailList({
mails,
groupedMails,
@@ -174,32 +242,15 @@ export function MailList({
>
{groupedMails && groupedMails.length > 0 ? (
groupedMails.map((group) => (
<li key={group.key} className="bg-secondary-50/50">
<div className="flex items-center gap-2 px-3 py-2 bg-secondary-100/70 sticky top-0 z-10">
<ChevronDown className="w-3.5 h-3.5 text-secondary-500" />
<span className="text-xs font-semibold text-secondary-700">{group.label}</span>
<span className="text-[10px] text-secondary-400">({group.mails.length})</span>
</div>
<ul className="divide-y divide-secondary-100">
{group.mails.map((mail) => renderMailItem(mail))}
</ul>
{group.subGroups && group.subGroups.length > 0 && (
<ul className="pl-3 border-l border-secondary-200">
{group.subGroups.map((sub) => (
<li key={sub.key}>
<div className="flex items-center gap-2 px-3 py-1.5 bg-secondary-50">
<ChevronDown className="w-3 h-3 text-secondary-400" />
<span className="text-[11px] font-medium text-secondary-600">{sub.label}</span>
<span className="text-[10px] text-secondary-400">({sub.mails.length})</span>
</div>
<ul className="divide-y divide-secondary-100">
{sub.mails.map((mail) => renderMailItem(mail))}
</ul>
</li>
))}
</ul>
)}
</li>
<GroupSection
key={group.key}
group={group}
selectedMailId={selectedMailId}
selectedMailIds={selectedMailIds}
onSelectMail={onSelectMail}
onToggleSelect={onToggleSelect}
renderMailItem={renderMailItem}
/>
))
) : (
mails.map((mail) => renderMailItem(mail))