feat: mail grouping with group headers in MailList, connected to GroupPanel
This commit is contained in:
@@ -9,11 +9,13 @@ 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 } from 'lucide-react';
|
||||
import { Loader2, Paperclip, Star, ChevronDown } from 'lucide-react';
|
||||
import { formatSmartDate } from '@/utils/date';
|
||||
import type { GroupedMails } from '@/components/mail/MailGroupPanel';
|
||||
|
||||
export interface MailListProps {
|
||||
mails: Mail[];
|
||||
groupedMails?: GroupedMails[] | null;
|
||||
selectedMailId: string | null;
|
||||
onSelectMail: (mail: Mail) => void;
|
||||
loading: boolean;
|
||||
@@ -30,6 +32,7 @@ function formatDate(dateStr: string): string {
|
||||
|
||||
export function MailList({
|
||||
mails,
|
||||
groupedMails,
|
||||
selectedMailId,
|
||||
onSelectMail,
|
||||
loading,
|
||||
@@ -161,7 +164,7 @@ export function MailList({
|
||||
{loading && mails.length > 0 && <Loader2 className="w-4 h-4 animate-spin text-secondary-400" />}
|
||||
</div>
|
||||
|
||||
{/* Mail list — infinite scroll, no pagination */}
|
||||
{/* Mail list — infinite scroll with optional grouping */}
|
||||
<ul
|
||||
ref={scrollRef}
|
||||
className="divide-y divide-secondary-100 flex-1 overflow-y-auto"
|
||||
@@ -169,7 +172,38 @@ export function MailList({
|
||||
data-testid="mail-list-items"
|
||||
onScroll={handleScroll}
|
||||
>
|
||||
{mails.map((mail) => renderMailItem(mail))}
|
||||
{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>
|
||||
))
|
||||
) : (
|
||||
mails.map((mail) => renderMailItem(mail))
|
||||
)}
|
||||
{loading && mails.length > 0 && (
|
||||
<li className="flex items-center justify-center py-4">
|
||||
<Loader2 className="w-5 h-5 animate-spin text-secondary-400" />
|
||||
|
||||
Reference in New Issue
Block a user