fix: mail grouping collapsible groups, no sticky header, recursive subgroups with all mails
This commit is contained in:
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user