feat(email): incoming mail UI - IMAP config block + Received emails tab

Frontend for the incoming-mail feature.

- Settings -> Email: an "Incoming mail (IMAP)" block under the outgoing SMTP
  settings (same field shape: host/port/security/user/pass/folder), shown only
  when the incomingMail flag is on (IncomingMailConfigCard, self-contained
  load/save).
- A "Received emails" tab next to "Sent emails" (ReceivedEmailsPanel) listing
  the received_emails log with from/subject/received/status + attachment count
  and a link to the incoming-invoices inbox.
- `incomingMail` flag in the frontend (type + context default, standalone) +
  a Communication-section Features card.
- email.service: getIncomingConfig / updateIncomingConfig / listReceived.
- i18n: settings.features.incomingMail, email.incoming, email.received (EN+DE).

Verified: tsc --noEmit clean (0 errors); en/de JSON valid; npm run build green.
This commit is contained in:
Luca
2026-06-11 16:19:55 +02:00
parent 5645c304ab
commit 31280e1f7a
9 changed files with 287 additions and 1 deletions
+39
View File
@@ -79,6 +79,32 @@ export interface EmailPreview {
body_text: string;
}
export interface IncomingMailConfig {
imap_host: string;
imap_port: number;
imap_secure: boolean;
imap_user: string;
imap_pass: string;
imap_folder: string;
}
export interface ReceivedEmail {
id: number;
message_id: string | null;
from_address: string | null;
subject: string | null;
received_at: string | null;
attachment_count: number;
status: string;
inbound_document_id: number | null;
error: string | null;
}
export interface ReceivedEmailsResponse {
items: ReceivedEmail[];
pagination: { page: number; pageSize: number; total: number; totalPages: number };
}
export const emailService = {
// Get email configuration
async getConfig(): Promise<EmailConfig> {
@@ -91,6 +117,19 @@ export const emailService = {
await api.post('/admin/email/config', config);
},
// Incoming mail (IMAP) configuration
async getIncomingConfig(): Promise<IncomingMailConfig> {
const response = await api.get<IncomingMailConfig>('/admin/email/incoming-config');
return response.data;
},
async updateIncomingConfig(config: IncomingMailConfig): Promise<void> {
await api.post('/admin/email/incoming-config', config);
},
async listReceived(params: { page?: number; pageSize?: number } = {}): Promise<ReceivedEmailsResponse> {
const response = await api.get<ReceivedEmailsResponse>('/admin/email/received', { params });
return response.data;
},
// Test email configuration
async testEmail(testEmail: string): Promise<void> {
await api.post('/admin/email/test', { test_email: testEmail });