Skip to content

Commit 2fb4a2c

Browse files
committed
feat(email): sending logs and records
1 parent fe04637 commit 2fb4a2c

12 files changed

Lines changed: 1220 additions & 10 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function Loading() {
2+
return null;
3+
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
'use client';
2+
3+
import { useEffect, useState } from 'react';
4+
import { useRouter, useSearchParams } from 'next/navigation';
5+
import { EmailRecord } from '@/lib/models/email';
6+
import { EmailFilters } from '@/components/email/records/email-filters';
7+
import { EmailDetail } from '@/components/email/records/email-detail';
8+
import { EmailList } from '@/components/email/records/email-list';
9+
import { fetchRecords } from '@/lib/api/email';
10+
11+
export default function EmailPage() {
12+
const searchParams = useSearchParams();
13+
const router = useRouter();
14+
const [emails, setEmails] = useState<EmailRecord[]>([]);
15+
const [loading, setLoading] = useState(true);
16+
const [totalCount, setTotalCount] = useState(0);
17+
const [selectedEmail, setSelectedEmail] = useState<EmailRecord | null>(null);
18+
const [isDetailOpen, setIsDetailOpen] = useState(false);
19+
20+
// Parse query params
21+
const messageId = searchParams.get('messageId') || undefined;
22+
const templateId = searchParams.get('templateId') || undefined;
23+
const receiver = searchParams.get('receiver') || undefined;
24+
const sender = searchParams.get('sender') || undefined;
25+
const cc = searchParams.get('cc')
26+
? searchParams.get('cc')?.split(',')
27+
: undefined;
28+
const replyTo = searchParams.get('replyTo') || undefined;
29+
const startDate = searchParams.get('startDate') || undefined;
30+
const endDate = searchParams.get('endDate') || undefined;
31+
const skip = Number.parseInt(searchParams.get('skip') || '0');
32+
const limit = 10; // Fixed page size
33+
const sort = searchParams.get('sort') || '-createdAt'; // Default sort by newest
34+
35+
// Fetch emails when query params change
36+
useEffect(() => {
37+
const getEmails = async () => {
38+
setLoading(true);
39+
try {
40+
const { records, count } = await fetchRecords({
41+
messageId,
42+
templateId,
43+
receiver,
44+
sender,
45+
cc,
46+
replyTo,
47+
startDate,
48+
endDate,
49+
skip,
50+
limit,
51+
sort,
52+
});
53+
setEmails(records);
54+
setTotalCount(count);
55+
} catch (error) {
56+
console.error('Failed to fetch emails:', error);
57+
} finally {
58+
setLoading(false);
59+
}
60+
};
61+
62+
getEmails();
63+
}, [
64+
messageId,
65+
templateId,
66+
receiver,
67+
sender,
68+
cc,
69+
replyTo,
70+
startDate,
71+
endDate,
72+
skip,
73+
limit,
74+
sort,
75+
]);
76+
77+
// Update query params
78+
const updateQueryParams = (params: Record<string, string | undefined>) => {
79+
const newParams = new URLSearchParams(searchParams.toString());
80+
81+
// Update or remove params
82+
Object.entries(params).forEach(([key, value]) => {
83+
if (value === undefined || value === '') {
84+
newParams.delete(key);
85+
} else {
86+
newParams.set(key, value);
87+
}
88+
});
89+
90+
// Reset skip when filters change
91+
if (!Object.keys(params).includes('skip')) {
92+
newParams.set('skip', '0');
93+
}
94+
95+
router.push(`/email/records?${newParams.toString()}`);
96+
};
97+
98+
const handleOpenDetail = (email: EmailRecord) => {
99+
setSelectedEmail(email);
100+
setIsDetailOpen(true);
101+
};
102+
103+
const handleCloseDetail = () => {
104+
setIsDetailOpen(false);
105+
};
106+
107+
return (
108+
<div className="container mx-auto py-6 space-y-6">
109+
<h1 className="text-3xl font-bold">Email Management</h1>
110+
111+
<EmailFilters
112+
initialFilters={{
113+
messageId,
114+
templateId,
115+
receiver,
116+
sender,
117+
cc: cc?.join(','),
118+
replyTo,
119+
startDate,
120+
endDate,
121+
}}
122+
onFilterChange={updateQueryParams}
123+
/>
124+
125+
<EmailList
126+
emails={emails}
127+
loading={loading}
128+
totalCount={totalCount}
129+
currentPage={Math.floor(skip / limit) + 1}
130+
pageSize={limit}
131+
onPageChange={page =>
132+
updateQueryParams({ skip: ((page - 1) * limit).toString() })
133+
}
134+
onSortChange={sortField => updateQueryParams({ sort: sortField })}
135+
currentSort={sort}
136+
onViewEmail={handleOpenDetail}
137+
/>
138+
139+
{selectedEmail && (
140+
<EmailDetail
141+
email={selectedEmail}
142+
isOpen={isDetailOpen}
143+
onClose={handleCloseDetail}
144+
/>
145+
)}
146+
</div>
147+
);
148+
}

0 commit comments

Comments
 (0)