feat(07-06): settings-api client + SmtpSettingsForm + SMTP page (DKV-05)
- settings-api.ts: fetchSmtp/saveSmtp/testSmtp with credentials:'include'; SmtpConfig exposes only hasPassword (T-07-17) - smtp-settings-form.tsx: Surface C form with show/hide password toggle, test-feedback auto-clears 6s - settings/general/smtp/page.tsx: SmtpSettingsPage heading + SmtpSettingsForm - de.json + en.json: add smtp.showPassword/hidePassword/testTesting/testSuccess/testFailed keys - TDD GREEN: 5/5 tests pass; aria-hidden* on required markers removed for correct getByLabelText matching
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* Settings API client — SMTP configuration.
|
||||
* Consumes the SettingsController built in 07-03.
|
||||
* All calls use credentials: 'include' for cookie-based auth.
|
||||
*
|
||||
* T-07-17: SmtpConfig exposes only hasPassword, never the secret.
|
||||
* The password field is never pre-filled from server data.
|
||||
*/
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
||||
|
||||
// --- Types mirroring the 07-03 backend contract ---
|
||||
|
||||
/**
|
||||
* SMTP configuration as returned by GET /settings/smtp.
|
||||
* encryptedPassword is NEVER returned (T-07-17).
|
||||
*/
|
||||
export interface SmtpConfig {
|
||||
host: string;
|
||||
port: number;
|
||||
encryption: 'none' | 'starttls' | 'ssl-tls';
|
||||
username?: string;
|
||||
fromAddress: string;
|
||||
/** True when an encrypted password is stored; the password value is never exposed. */
|
||||
hasPassword: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Payload for PUT /settings/smtp and POST /settings/smtp/test.
|
||||
* password is optional — omit to preserve the existing stored password.
|
||||
*/
|
||||
export interface SaveSmtpPayload {
|
||||
host: string;
|
||||
port: number;
|
||||
encryption: 'none' | 'starttls' | 'ssl-tls';
|
||||
username?: string;
|
||||
/** Only include when the user has typed a new password. */
|
||||
password?: string;
|
||||
fromAddress: string;
|
||||
}
|
||||
|
||||
// --- API functions ---
|
||||
|
||||
/**
|
||||
* Fetch the SMTP configuration for the current tenant.
|
||||
* GET /settings/smtp
|
||||
* Returns null when no configuration has been saved yet (404).
|
||||
*/
|
||||
export async function fetchSmtp(): Promise<SmtpConfig | null> {
|
||||
const res = await fetch(`${API_URL}/settings/smtp`, {
|
||||
credentials: 'include',
|
||||
});
|
||||
if (res.status === 404) return null;
|
||||
if (!res.ok) throw new Error('Failed to fetch SMTP config');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the SMTP configuration.
|
||||
* PUT /settings/smtp
|
||||
*/
|
||||
export async function saveSmtp(payload: SaveSmtpPayload): Promise<SmtpConfig> {
|
||||
const res = await fetch(`${API_URL}/settings/smtp`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to save SMTP config');
|
||||
return res.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the SMTP connection with the given settings.
|
||||
* POST /settings/smtp/test
|
||||
* Returns { success: boolean } — backend runs nodemailer.verify().
|
||||
*/
|
||||
export async function testSmtp(
|
||||
payload: SaveSmtpPayload,
|
||||
): Promise<{ success: boolean }> {
|
||||
const res = await fetch(`${API_URL}/settings/smtp/test`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
credentials: 'include',
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!res.ok) throw new Error('Failed to test SMTP config');
|
||||
return res.json();
|
||||
}
|
||||
Reference in New Issue
Block a user