feat: Multi-email ticketing system with platform email addresses
- Add PlatformEmailAddress model for managing platform-level email addresses - Add TicketEmailAddress model for tenant-level email addresses - Create MailServerService for IMAP integration with mail.talova.net - Implement PlatformEmailReceiver for processing incoming platform emails - Add email autoconfiguration for Mozilla, Microsoft, and Apple clients - Add configurable email polling interval in platform settings - Add "Check Emails" button on support page for manual refresh - Add ticket counts to status tabs on support page - Add platform email addresses management page - Add Privacy Policy and Terms of Service pages - Add robots.txt for SEO - Restrict email addresses to smoothschedule.com domain only 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
157
frontend/src/api/ticketEmailAddresses.ts
Normal file
157
frontend/src/api/ticketEmailAddresses.ts
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* API client for Ticket Email Addresses
|
||||
*/
|
||||
|
||||
import apiClient from './client';
|
||||
|
||||
export interface TicketEmailAddress {
|
||||
id: number;
|
||||
tenant: number;
|
||||
tenant_name: string;
|
||||
display_name: string;
|
||||
email_address: string;
|
||||
color: string;
|
||||
imap_host: string;
|
||||
imap_port: number;
|
||||
imap_use_ssl: boolean;
|
||||
imap_username: string;
|
||||
imap_password?: string;
|
||||
imap_folder: string;
|
||||
smtp_host: string;
|
||||
smtp_port: number;
|
||||
smtp_use_tls: boolean;
|
||||
smtp_use_ssl: boolean;
|
||||
smtp_username: string;
|
||||
smtp_password?: string;
|
||||
is_active: boolean;
|
||||
is_default: boolean;
|
||||
last_check_at?: string;
|
||||
last_error?: string;
|
||||
emails_processed_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
is_imap_configured: boolean;
|
||||
is_smtp_configured: boolean;
|
||||
is_fully_configured: boolean;
|
||||
}
|
||||
|
||||
export interface TicketEmailAddressListItem {
|
||||
id: number;
|
||||
display_name: string;
|
||||
email_address: string;
|
||||
color: string;
|
||||
is_active: boolean;
|
||||
is_default: boolean;
|
||||
last_check_at?: string;
|
||||
emails_processed_count: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface TicketEmailAddressCreate {
|
||||
display_name: string;
|
||||
email_address: string;
|
||||
color: string;
|
||||
imap_host: string;
|
||||
imap_port: number;
|
||||
imap_use_ssl: boolean;
|
||||
imap_username: string;
|
||||
imap_password: string;
|
||||
imap_folder: string;
|
||||
smtp_host: string;
|
||||
smtp_port: number;
|
||||
smtp_use_tls: boolean;
|
||||
smtp_use_ssl: boolean;
|
||||
smtp_username: string;
|
||||
smtp_password: string;
|
||||
is_active: boolean;
|
||||
is_default: boolean;
|
||||
}
|
||||
|
||||
export interface TestConnectionResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface FetchEmailsResponse {
|
||||
success: boolean;
|
||||
message: string;
|
||||
processed?: number;
|
||||
errors?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all ticket email addresses for the current business
|
||||
*/
|
||||
export const getTicketEmailAddresses = async (): Promise<TicketEmailAddressListItem[]> => {
|
||||
const response = await apiClient.get('/tickets/email-addresses/');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a specific ticket email address by ID
|
||||
*/
|
||||
export const getTicketEmailAddress = async (id: number): Promise<TicketEmailAddress> => {
|
||||
const response = await apiClient.get(`/tickets/email-addresses/${id}/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new ticket email address
|
||||
*/
|
||||
export const createTicketEmailAddress = async (
|
||||
data: TicketEmailAddressCreate
|
||||
): Promise<TicketEmailAddress> => {
|
||||
const response = await apiClient.post('/tickets/email-addresses/', data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update an existing ticket email address
|
||||
*/
|
||||
export const updateTicketEmailAddress = async (
|
||||
id: number,
|
||||
data: Partial<TicketEmailAddressCreate>
|
||||
): Promise<TicketEmailAddress> => {
|
||||
const response = await apiClient.patch(`/tickets/email-addresses/${id}/`, data);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Delete a ticket email address
|
||||
*/
|
||||
export const deleteTicketEmailAddress = async (id: number): Promise<void> => {
|
||||
await apiClient.delete(`/tickets/email-addresses/${id}/`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Test IMAP connection for an email address
|
||||
*/
|
||||
export const testImapConnection = async (id: number): Promise<TestConnectionResponse> => {
|
||||
const response = await apiClient.post(`/tickets/email-addresses/${id}/test_imap/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Test SMTP connection for an email address
|
||||
*/
|
||||
export const testSmtpConnection = async (id: number): Promise<TestConnectionResponse> => {
|
||||
const response = await apiClient.post(`/tickets/email-addresses/${id}/test_smtp/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Manually fetch emails for an email address
|
||||
*/
|
||||
export const fetchEmailsNow = async (id: number): Promise<FetchEmailsResponse> => {
|
||||
const response = await apiClient.post(`/tickets/email-addresses/${id}/fetch_now/`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set an email address as the default for the business
|
||||
*/
|
||||
export const setAsDefault = async (id: number): Promise<{ success: boolean; message: string }> => {
|
||||
const response = await apiClient.post(`/tickets/email-addresses/${id}/set_as_default/`);
|
||||
return response.data;
|
||||
};
|
||||
Reference in New Issue
Block a user