When VITE_API_URL=/api, axios baseURL is already set to /api. However, all endpoint calls included the /api/ prefix, creating double paths like /api/api/auth/login/. Removed /api/ prefix from 81 API endpoint calls across 22 files: - src/api/auth.ts - Fixed login, logout, me, refresh, hijack endpoints - src/api/client.ts - Fixed token refresh endpoint - src/api/profile.ts - Fixed all profile, email, password, MFA, sessions endpoints - src/hooks/*.ts - Fixed all remaining API calls (users, appointments, resources, etc) - src/pages/*.tsx - Fixed signup and email verification endpoints This ensures API requests use the correct path: /api/auth/login/ instead of /api/api/auth/login/ 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
263 lines
6.7 KiB
TypeScript
263 lines
6.7 KiB
TypeScript
/**
|
|
* API client for ticket email settings
|
|
*/
|
|
|
|
import apiClient from './client';
|
|
|
|
export interface TicketEmailSettings {
|
|
// IMAP settings (inbound)
|
|
imap_host: string;
|
|
imap_port: number;
|
|
imap_use_ssl: boolean;
|
|
imap_username: string;
|
|
imap_password_masked: string;
|
|
imap_folder: string;
|
|
// SMTP settings (outbound)
|
|
smtp_host: string;
|
|
smtp_port: number;
|
|
smtp_use_tls: boolean;
|
|
smtp_use_ssl: boolean;
|
|
smtp_username: string;
|
|
smtp_password_masked: string;
|
|
smtp_from_email: string;
|
|
smtp_from_name: string;
|
|
// General settings
|
|
support_email_address: string;
|
|
support_email_domain: string;
|
|
is_enabled: boolean;
|
|
delete_after_processing: boolean;
|
|
check_interval_seconds: number;
|
|
max_attachment_size_mb: number;
|
|
allowed_attachment_types: string[];
|
|
// Status
|
|
last_check_at: string | null;
|
|
last_error: string;
|
|
emails_processed_count: number;
|
|
is_configured: boolean;
|
|
is_imap_configured: boolean;
|
|
is_smtp_configured: boolean;
|
|
created_at: string;
|
|
updated_at: string;
|
|
}
|
|
|
|
export interface TicketEmailSettingsUpdate {
|
|
// IMAP settings
|
|
imap_host?: string;
|
|
imap_port?: number;
|
|
imap_use_ssl?: boolean;
|
|
imap_username?: string;
|
|
imap_password?: string;
|
|
imap_folder?: string;
|
|
// SMTP settings
|
|
smtp_host?: string;
|
|
smtp_port?: number;
|
|
smtp_use_tls?: boolean;
|
|
smtp_use_ssl?: boolean;
|
|
smtp_username?: string;
|
|
smtp_password?: string;
|
|
smtp_from_email?: string;
|
|
smtp_from_name?: string;
|
|
// General settings
|
|
support_email_address?: string;
|
|
support_email_domain?: string;
|
|
is_enabled?: boolean;
|
|
delete_after_processing?: boolean;
|
|
check_interval_seconds?: number;
|
|
max_attachment_size_mb?: number;
|
|
allowed_attachment_types?: string[];
|
|
}
|
|
|
|
export interface TestConnectionResult {
|
|
success: boolean;
|
|
message: string;
|
|
}
|
|
|
|
export interface FetchNowResult {
|
|
success: boolean;
|
|
message: string;
|
|
processed: number;
|
|
}
|
|
|
|
export interface EmailProviderDetectResult {
|
|
success: boolean;
|
|
email: string;
|
|
domain: string;
|
|
detected: boolean;
|
|
detected_via?: 'domain_lookup' | 'mx_record';
|
|
provider: 'google' | 'microsoft' | 'yahoo' | 'apple' | 'aol' | 'zoho' | 'protonmail' | 'unknown';
|
|
display_name: string;
|
|
imap_host?: string;
|
|
imap_port?: number;
|
|
smtp_host?: string;
|
|
smtp_port?: number;
|
|
oauth_supported: boolean;
|
|
message?: string;
|
|
notes?: string;
|
|
suggested_imap_port?: number;
|
|
suggested_smtp_port?: number;
|
|
}
|
|
|
|
export interface IncomingTicketEmail {
|
|
id: number;
|
|
message_id: string;
|
|
from_address: string;
|
|
from_name: string;
|
|
to_address: string;
|
|
subject: string;
|
|
body_text: string;
|
|
extracted_reply: string;
|
|
ticket: number | null;
|
|
ticket_subject: string;
|
|
matched_user: number | null;
|
|
ticket_id_from_email: string;
|
|
processing_status: 'PENDING' | 'PROCESSED' | 'FAILED' | 'SPAM' | 'NO_MATCH' | 'DUPLICATE';
|
|
processing_status_display: string;
|
|
error_message: string;
|
|
email_date: string;
|
|
received_at: string;
|
|
processed_at: string | null;
|
|
}
|
|
|
|
/**
|
|
* Get ticket email settings
|
|
*/
|
|
export const getTicketEmailSettings = async (): Promise<TicketEmailSettings> => {
|
|
const response = await apiClient.get('/tickets/email-settings/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Update ticket email settings
|
|
*/
|
|
export const updateTicketEmailSettings = async (
|
|
data: TicketEmailSettingsUpdate
|
|
): Promise<TicketEmailSettings> => {
|
|
const response = await apiClient.patch('/tickets/email-settings/', data);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Test IMAP connection
|
|
*/
|
|
export const testImapConnection = async (): Promise<TestConnectionResult> => {
|
|
const response = await apiClient.post('/tickets/email-settings/test-imap/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Test SMTP connection
|
|
*/
|
|
export const testSmtpConnection = async (): Promise<TestConnectionResult> => {
|
|
const response = await apiClient.post('/tickets/email-settings/test-smtp/');
|
|
return response.data;
|
|
};
|
|
|
|
// Legacy alias for backwards compatibility
|
|
export const testEmailConnection = testImapConnection;
|
|
|
|
/**
|
|
* Manually trigger email fetch
|
|
*/
|
|
export const fetchEmailsNow = async (): Promise<FetchNowResult> => {
|
|
const response = await apiClient.post('/tickets/email-settings/fetch-now/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Get incoming email audit log
|
|
*/
|
|
export const getIncomingEmails = async (params?: {
|
|
status?: string;
|
|
ticket?: number;
|
|
}): Promise<IncomingTicketEmail[]> => {
|
|
const response = await apiClient.get('/tickets/incoming-emails/', { params });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Reprocess a failed incoming email
|
|
*/
|
|
export const reprocessIncomingEmail = async (id: number): Promise<{
|
|
success: boolean;
|
|
message: string;
|
|
comment_id?: number;
|
|
ticket_id?: number;
|
|
}> => {
|
|
const response = await apiClient.post(`/tickets/incoming-emails/${id}/reprocess/`);
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Detect email provider from email address
|
|
* Auto-detects Gmail, Outlook, Yahoo, iCloud, etc. from domain
|
|
* Also checks MX records for custom domains using Google Workspace or Microsoft 365
|
|
*/
|
|
export const detectEmailProvider = async (email: string): Promise<EmailProviderDetectResult> => {
|
|
const response = await apiClient.post('/tickets/email-settings/detect/', { email });
|
|
return response.data;
|
|
};
|
|
|
|
// OAuth types and functions
|
|
export interface OAuthStatusResult {
|
|
google: { configured: boolean };
|
|
microsoft: { configured: boolean };
|
|
}
|
|
|
|
export interface OAuthInitiateResult {
|
|
success: boolean;
|
|
authorization_url?: string;
|
|
error?: string;
|
|
}
|
|
|
|
export interface OAuthCredential {
|
|
id: number;
|
|
provider: 'google' | 'microsoft';
|
|
email: string;
|
|
purpose: string;
|
|
is_valid: boolean;
|
|
is_expired: boolean;
|
|
last_used_at: string | null;
|
|
last_error: string;
|
|
created_at: string;
|
|
}
|
|
|
|
/**
|
|
* Get OAuth configuration status
|
|
*/
|
|
export const getOAuthStatus = async (): Promise<OAuthStatusResult> => {
|
|
const response = await apiClient.get('/oauth/status/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Initiate Google OAuth flow
|
|
*/
|
|
export const initiateGoogleOAuth = async (purpose: string = 'email'): Promise<OAuthInitiateResult> => {
|
|
const response = await apiClient.post('/oauth/google/initiate/', { purpose });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Initiate Microsoft OAuth flow
|
|
*/
|
|
export const initiateMicrosoftOAuth = async (purpose: string = 'email'): Promise<OAuthInitiateResult> => {
|
|
const response = await apiClient.post('/oauth/microsoft/initiate/', { purpose });
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* List OAuth credentials
|
|
*/
|
|
export const getOAuthCredentials = async (): Promise<OAuthCredential[]> => {
|
|
const response = await apiClient.get('/oauth/credentials/');
|
|
return response.data;
|
|
};
|
|
|
|
/**
|
|
* Delete OAuth credential
|
|
*/
|
|
export const deleteOAuthCredential = async (id: number): Promise<{ success: boolean; message: string }> => {
|
|
const response = await apiClient.delete(`/oauth/credentials/${id}/`);
|
|
return response.data;
|
|
};
|