Fix double /api/ prefix in API endpoint calls

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>
This commit is contained in:
poduck
2025-11-30 15:27:57 -05:00
parent f1d4dac9d2
commit 4cd6610f2a
53 changed files with 476 additions and 687 deletions

View File

@@ -64,7 +64,7 @@ export interface User {
* Login user
*/
export const login = async (credentials: LoginCredentials): Promise<LoginResponse> => {
const response = await apiClient.post<LoginResponse>('/api/auth/login/', credentials);
const response = await apiClient.post<LoginResponse>('/auth/login/', credentials);
return response.data;
};
@@ -72,14 +72,14 @@ export const login = async (credentials: LoginCredentials): Promise<LoginRespons
* Logout user
*/
export const logout = async (): Promise<void> => {
await apiClient.post('/api/auth/logout/');
await apiClient.post('/auth/logout/');
};
/**
* Get current user
*/
export const getCurrentUser = async (): Promise<User> => {
const response = await apiClient.get<User>('/api/auth/me/');
const response = await apiClient.get<User>('/auth/me/');
return response.data;
};
@@ -87,7 +87,7 @@ export const getCurrentUser = async (): Promise<User> => {
* Refresh access token
*/
export const refreshToken = async (refresh: string): Promise<{ access: string }> => {
const response = await apiClient.post('/api/auth/refresh/', { refresh });
const response = await apiClient.post('/auth/refresh/', { refresh });
return response.data;
};
@@ -99,7 +99,7 @@ export const masquerade = async (
hijack_history?: MasqueradeStackEntry[]
): Promise<LoginResponse> => {
const response = await apiClient.post<LoginResponse>(
'/api/auth/hijack/acquire/',
'/auth/hijack/acquire/',
{ user_pk, hijack_history }
);
return response.data;
@@ -112,7 +112,7 @@ export const stopMasquerade = async (
masquerade_stack: MasqueradeStackEntry[]
): Promise<LoginResponse> => {
const response = await apiClient.post<LoginResponse>(
'/api/auth/hijack/release/',
'/auth/hijack/release/',
{ masquerade_stack }
);
return response.data;

View File

@@ -71,7 +71,7 @@ apiClient.interceptors.response.use(
// Try to refresh token (from cookie)
const refreshToken = getCookie('refresh_token');
if (refreshToken) {
const response = await axios.post(`${API_BASE_URL}/api/auth/refresh/`, {
const response = await axios.post(`${API_BASE_URL}/auth/refresh/`, {
refresh: refreshToken,
});

View File

@@ -3,6 +3,8 @@
* Centralized configuration for API endpoints and settings
*/
import { getBaseDomain, isRootDomain } from '../utils/domain';
// Determine API base URL based on environment
const getApiBaseUrl = (): string => {
// In production, this would be set via environment variable
@@ -10,8 +12,15 @@ const getApiBaseUrl = (): string => {
return import.meta.env.VITE_API_URL;
}
// Development: use api subdomain
return 'http://api.lvh.me:8000';
// Development: build API URL dynamically based on current domain
const baseDomain = getBaseDomain();
const protocol = window.location.protocol;
// For localhost or lvh.me, use port 8000
const isDev = baseDomain === 'localhost' || baseDomain === 'lvh.me';
const port = isDev ? ':8000' : '';
return `${protocol}//api.${baseDomain}${port}`;
};
export const API_BASE_URL = getApiBaseUrl();
@@ -24,8 +33,8 @@ export const getSubdomain = (): string | null => {
const hostname = window.location.hostname;
const parts = hostname.split('.');
// lvh.me without subdomain (root domain) - no business context
if (hostname === 'lvh.me') {
// Root domain (no subdomain) - no business context
if (isRootDomain()) {
return null;
}

View File

@@ -90,7 +90,7 @@ export interface MFAVerifyResponse {
* Get current MFA status
*/
export const getMFAStatus = async (): Promise<MFAStatus> => {
const response = await apiClient.get<MFAStatus>('/api/auth/mfa/status/');
const response = await apiClient.get<MFAStatus>('/auth/mfa/status/');
return response.data;
};
@@ -102,7 +102,7 @@ export const getMFAStatus = async (): Promise<MFAStatus> => {
* Send phone verification code
*/
export const sendPhoneVerification = async (phone: string): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.post('/api/auth/mfa/phone/send/', { phone });
const response = await apiClient.post('/auth/mfa/phone/send/', { phone });
return response.data;
};
@@ -110,7 +110,7 @@ export const sendPhoneVerification = async (phone: string): Promise<{ success: b
* Verify phone number with code
*/
export const verifyPhone = async (code: string): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.post('/api/auth/mfa/phone/verify/', { code });
const response = await apiClient.post('/auth/mfa/phone/verify/', { code });
return response.data;
};
@@ -118,7 +118,7 @@ export const verifyPhone = async (code: string): Promise<{ success: boolean; mes
* Enable SMS MFA (requires verified phone)
*/
export const enableSMSMFA = async (): Promise<MFAEnableResponse> => {
const response = await apiClient.post<MFAEnableResponse>('/api/auth/mfa/sms/enable/');
const response = await apiClient.post<MFAEnableResponse>('/auth/mfa/sms/enable/');
return response.data;
};
@@ -130,7 +130,7 @@ export const enableSMSMFA = async (): Promise<MFAEnableResponse> => {
* Initialize TOTP setup (returns QR code and secret)
*/
export const setupTOTP = async (): Promise<TOTPSetupResponse> => {
const response = await apiClient.post<TOTPSetupResponse>('/api/auth/mfa/totp/setup/');
const response = await apiClient.post<TOTPSetupResponse>('/auth/mfa/totp/setup/');
return response.data;
};
@@ -138,7 +138,7 @@ export const setupTOTP = async (): Promise<TOTPSetupResponse> => {
* Verify TOTP code to complete setup
*/
export const verifyTOTPSetup = async (code: string): Promise<MFAEnableResponse> => {
const response = await apiClient.post<MFAEnableResponse>('/api/auth/mfa/totp/verify/', { code });
const response = await apiClient.post<MFAEnableResponse>('/auth/mfa/totp/verify/', { code });
return response.data;
};
@@ -150,7 +150,7 @@ export const verifyTOTPSetup = async (code: string): Promise<MFAEnableResponse>
* Generate new backup codes (invalidates old ones)
*/
export const generateBackupCodes = async (): Promise<BackupCodesResponse> => {
const response = await apiClient.post<BackupCodesResponse>('/api/auth/mfa/backup-codes/');
const response = await apiClient.post<BackupCodesResponse>('/auth/mfa/backup-codes/');
return response.data;
};
@@ -158,7 +158,7 @@ export const generateBackupCodes = async (): Promise<BackupCodesResponse> => {
* Get backup codes status
*/
export const getBackupCodesStatus = async (): Promise<BackupCodesStatus> => {
const response = await apiClient.get<BackupCodesStatus>('/api/auth/mfa/backup-codes/status/');
const response = await apiClient.get<BackupCodesStatus>('/auth/mfa/backup-codes/status/');
return response.data;
};
@@ -170,7 +170,7 @@ export const getBackupCodesStatus = async (): Promise<BackupCodesStatus> => {
* Disable MFA (requires password or valid MFA code)
*/
export const disableMFA = async (credentials: { password?: string; mfa_code?: string }): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.post('/api/auth/mfa/disable/', credentials);
const response = await apiClient.post('/auth/mfa/disable/', credentials);
return response.data;
};
@@ -182,7 +182,7 @@ export const disableMFA = async (credentials: { password?: string; mfa_code?: st
* Send MFA code for login (SMS only)
*/
export const sendMFALoginCode = async (userId: number, method: 'SMS' | 'TOTP' = 'SMS'): Promise<{ success: boolean; message: string; method: string }> => {
const response = await apiClient.post('/api/auth/mfa/login/send/', { user_id: userId, method });
const response = await apiClient.post('/auth/mfa/login/send/', { user_id: userId, method });
return response.data;
};
@@ -195,7 +195,7 @@ export const verifyMFALogin = async (
method: 'SMS' | 'TOTP' | 'BACKUP',
trustDevice: boolean = false
): Promise<MFAVerifyResponse> => {
const response = await apiClient.post<MFAVerifyResponse>('/api/auth/mfa/login/verify/', {
const response = await apiClient.post<MFAVerifyResponse>('/auth/mfa/login/verify/', {
user_id: userId,
code,
method,
@@ -212,7 +212,7 @@ export const verifyMFALogin = async (
* List trusted devices
*/
export const listTrustedDevices = async (): Promise<{ devices: TrustedDevice[] }> => {
const response = await apiClient.get('/api/auth/mfa/devices/');
const response = await apiClient.get('/auth/mfa/devices/');
return response.data;
};
@@ -220,7 +220,7 @@ export const listTrustedDevices = async (): Promise<{ devices: TrustedDevice[] }
* Revoke a specific trusted device
*/
export const revokeTrustedDevice = async (deviceId: number): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.delete(`/api/auth/mfa/devices/${deviceId}/`);
const response = await apiClient.delete(`/auth/mfa/devices/${deviceId}/`);
return response.data;
};
@@ -228,6 +228,6 @@ export const revokeTrustedDevice = async (deviceId: number): Promise<{ success:
* Revoke all trusted devices
*/
export const revokeAllTrustedDevices = async (): Promise<{ success: boolean; message: string; count: number }> => {
const response = await apiClient.delete('/api/auth/mfa/devices/revoke-all/');
const response = await apiClient.delete('/auth/mfa/devices/revoke-all/');
return response.data;
};

View File

@@ -29,7 +29,7 @@ export const getNotifications = async (params?: { read?: boolean; limit?: number
queryParams.append('limit', String(params.limit));
}
const query = queryParams.toString();
const url = query ? `/api/notifications/?${query}` : '/api/notifications/';
const url = query ? `/notifications/?${query}` : '/notifications/';
const response = await apiClient.get(url);
return response.data;
};
@@ -38,7 +38,7 @@ export const getNotifications = async (params?: { read?: boolean; limit?: number
* Get count of unread notifications
*/
export const getUnreadCount = async (): Promise<number> => {
const response = await apiClient.get<UnreadCountResponse>('/api/notifications/unread_count/');
const response = await apiClient.get<UnreadCountResponse>('/notifications/unread_count/');
return response.data.count;
};
@@ -46,19 +46,19 @@ export const getUnreadCount = async (): Promise<number> => {
* Mark a single notification as read
*/
export const markNotificationRead = async (id: number): Promise<void> => {
await apiClient.post(`/api/notifications/${id}/mark_read/`);
await apiClient.post(`/notifications/${id}/mark_read/`);
};
/**
* Mark all notifications as read
*/
export const markAllNotificationsRead = async (): Promise<void> => {
await apiClient.post('/api/notifications/mark_all_read/');
await apiClient.post('/notifications/mark_all_read/');
};
/**
* Delete all read notifications
*/
export const clearAllNotifications = async (): Promise<void> => {
await apiClient.delete('/api/notifications/clear_all/');
await apiClient.delete('/notifications/clear_all/');
};

View File

@@ -95,7 +95,7 @@ export interface AccountSessionResponse {
* Returns the complete payment setup for the business.
*/
export const getPaymentConfig = () =>
apiClient.get<PaymentConfig>('/api/payments/config/status/');
apiClient.get<PaymentConfig>('/payments/config/status/');
// ============================================================================
// API Keys (Free Tier)
@@ -105,14 +105,14 @@ export const getPaymentConfig = () =>
* Get current API key configuration (masked keys).
*/
export const getApiKeys = () =>
apiClient.get<ApiKeysCurrentResponse>('/api/payments/api-keys/');
apiClient.get<ApiKeysCurrentResponse>('/payments/api-keys/');
/**
* Save API keys.
* Validates and stores the provided Stripe API keys.
*/
export const saveApiKeys = (secretKey: string, publishableKey: string) =>
apiClient.post<ApiKeysInfo>('/api/payments/api-keys/', {
apiClient.post<ApiKeysInfo>('/payments/api-keys/', {
secret_key: secretKey,
publishable_key: publishableKey,
});
@@ -122,7 +122,7 @@ export const saveApiKeys = (secretKey: string, publishableKey: string) =>
* Tests the keys against Stripe API.
*/
export const validateApiKeys = (secretKey: string, publishableKey: string) =>
apiClient.post<ApiKeysValidationResult>('/api/payments/api-keys/validate/', {
apiClient.post<ApiKeysValidationResult>('/payments/api-keys/validate/', {
secret_key: secretKey,
publishable_key: publishableKey,
});
@@ -132,13 +132,13 @@ export const validateApiKeys = (secretKey: string, publishableKey: string) =>
* Tests stored keys and updates their status.
*/
export const revalidateApiKeys = () =>
apiClient.post<ApiKeysValidationResult>('/api/payments/api-keys/revalidate/');
apiClient.post<ApiKeysValidationResult>('/payments/api-keys/revalidate/');
/**
* Delete stored API keys.
*/
export const deleteApiKeys = () =>
apiClient.delete<{ success: boolean; message: string }>('/api/payments/api-keys/delete/');
apiClient.delete<{ success: boolean; message: string }>('/payments/api-keys/delete/');
// ============================================================================
// Stripe Connect (Paid Tiers)
@@ -148,14 +148,14 @@ export const deleteApiKeys = () =>
* Get current Connect account status.
*/
export const getConnectStatus = () =>
apiClient.get<ConnectAccountInfo>('/api/payments/connect/status/');
apiClient.get<ConnectAccountInfo>('/payments/connect/status/');
/**
* Initiate Connect account onboarding.
* Returns a URL to redirect the user for Stripe onboarding.
*/
export const initiateConnectOnboarding = (refreshUrl: string, returnUrl: string) =>
apiClient.post<ConnectOnboardingResponse>('/api/payments/connect/onboard/', {
apiClient.post<ConnectOnboardingResponse>('/payments/connect/onboard/', {
refresh_url: refreshUrl,
return_url: returnUrl,
});
@@ -165,7 +165,7 @@ export const initiateConnectOnboarding = (refreshUrl: string, returnUrl: string)
* For custom Connect accounts that need a new onboarding link.
*/
export const refreshConnectOnboardingLink = (refreshUrl: string, returnUrl: string) =>
apiClient.post<{ url: string }>('/api/payments/connect/refresh-link/', {
apiClient.post<{ url: string }>('/payments/connect/refresh-link/', {
refresh_url: refreshUrl,
return_url: returnUrl,
});
@@ -175,14 +175,14 @@ export const refreshConnectOnboardingLink = (refreshUrl: string, returnUrl: stri
* Returns a client_secret for initializing Stripe's embedded Connect components.
*/
export const createAccountSession = () =>
apiClient.post<AccountSessionResponse>('/api/payments/connect/account-session/');
apiClient.post<AccountSessionResponse>('/payments/connect/account-session/');
/**
* Refresh Connect account status from Stripe.
* Syncs the local account record with the current state in Stripe.
*/
export const refreshConnectStatus = () =>
apiClient.post<ConnectAccountInfo>('/api/payments/connect/refresh-status/');
apiClient.post<ConnectAccountInfo>('/payments/connect/refresh-status/');
// ============================================================================
// Transaction Analytics
@@ -319,7 +319,7 @@ export const getTransactions = (filters?: TransactionFilters) => {
const queryString = params.toString();
return apiClient.get<TransactionListResponse>(
`/api/payments/transactions/${queryString ? `?${queryString}` : ''}`
`/payments/transactions/${queryString ? `?${queryString}` : ''}`
);
};
@@ -327,7 +327,7 @@ export const getTransactions = (filters?: TransactionFilters) => {
* Get a single transaction by ID.
*/
export const getTransaction = (id: number) =>
apiClient.get<Transaction>(`/api/payments/transactions/${id}/`);
apiClient.get<Transaction>(`/payments/transactions/${id}/`);
/**
* Get transaction summary/analytics.
@@ -339,7 +339,7 @@ export const getTransactionSummary = (filters?: Pick<TransactionFilters, 'start_
const queryString = params.toString();
return apiClient.get<TransactionSummary>(
`/api/payments/transactions/summary/${queryString ? `?${queryString}` : ''}`
`/payments/transactions/summary/${queryString ? `?${queryString}` : ''}`
);
};
@@ -347,26 +347,26 @@ export const getTransactionSummary = (filters?: Pick<TransactionFilters, 'start_
* Get charges from Stripe API.
*/
export const getStripeCharges = (limit: number = 20) =>
apiClient.get<ChargesResponse>(`/api/payments/transactions/charges/?limit=${limit}`);
apiClient.get<ChargesResponse>(`/payments/transactions/charges/?limit=${limit}`);
/**
* Get payouts from Stripe API.
*/
export const getStripePayouts = (limit: number = 20) =>
apiClient.get<PayoutsResponse>(`/api/payments/transactions/payouts/?limit=${limit}`);
apiClient.get<PayoutsResponse>(`/payments/transactions/payouts/?limit=${limit}`);
/**
* Get current balance from Stripe API.
*/
export const getStripeBalance = () =>
apiClient.get<BalanceResponse>('/api/payments/transactions/balance/');
apiClient.get<BalanceResponse>('/payments/transactions/balance/');
/**
* Export transaction data.
* Returns the file data directly for download.
*/
export const exportTransactions = (request: ExportRequest) =>
apiClient.post('/api/payments/transactions/export/', request, {
apiClient.post('/payments/transactions/export/', request, {
responseType: 'blob',
});
@@ -422,7 +422,7 @@ export interface RefundResponse {
* Get detailed transaction information including refund data.
*/
export const getTransactionDetail = (id: number) =>
apiClient.get<TransactionDetail>(`/api/payments/transactions/${id}/`);
apiClient.get<TransactionDetail>(`/payments/transactions/${id}/`);
/**
* Issue a refund for a transaction.
@@ -430,4 +430,4 @@ export const getTransactionDetail = (id: number) =>
* @param request - Optional refund request with amount and reason
*/
export const refundTransaction = (transactionId: number, request?: RefundRequest) =>
apiClient.post<RefundResponse>(`/api/payments/transactions/${transactionId}/refund/`, request || {});
apiClient.post<RefundResponse>(`/payments/transactions/${transactionId}/refund/`, request || {});

View File

@@ -75,7 +75,7 @@ export interface PlatformOAuthSettingsUpdate {
* Get platform OAuth settings
*/
export const getPlatformOAuthSettings = async (): Promise<PlatformOAuthSettings> => {
const { data } = await apiClient.get('/api/platform/settings/oauth/');
const { data } = await apiClient.get('/platform/settings/oauth/');
return data;
};
@@ -85,6 +85,6 @@ export const getPlatformOAuthSettings = async (): Promise<PlatformOAuthSettings>
export const updatePlatformOAuthSettings = async (
settings: PlatformOAuthSettingsUpdate
): Promise<PlatformOAuthSettings> => {
const { data } = await apiClient.post('/api/platform/settings/oauth/', settings);
const { data } = await apiClient.post('/platform/settings/oauth/', settings);
return data;
};

View File

@@ -71,43 +71,43 @@ export interface LoginHistoryEntry {
// Profile API
export const getProfile = async (): Promise<UserProfile> => {
const response = await apiClient.get('/api/auth/profile/');
const response = await apiClient.get('/auth/profile/');
return response.data;
};
export const updateProfile = async (data: Partial<UserProfile>): Promise<UserProfile> => {
const response = await apiClient.patch('/api/auth/profile/', data);
const response = await apiClient.patch('/auth/profile/', data);
return response.data;
};
export const uploadAvatar = async (file: File): Promise<{ avatar_url: string }> => {
const formData = new FormData();
formData.append('avatar', file);
const response = await apiClient.post('/api/auth/profile/avatar/', formData, {
const response = await apiClient.post('/auth/profile/avatar/', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return response.data;
};
export const deleteAvatar = async (): Promise<void> => {
await apiClient.delete('/api/auth/profile/avatar/');
await apiClient.delete('/auth/profile/avatar/');
};
// Email API
export const sendVerificationEmail = async (): Promise<void> => {
await apiClient.post('/api/auth/email/verify/send/');
await apiClient.post('/auth/email/verify/send/');
};
export const verifyEmail = async (token: string): Promise<void> => {
await apiClient.post('/api/auth/email/verify/confirm/', { token });
await apiClient.post('/auth/email/verify/confirm/', { token });
};
export const requestEmailChange = async (newEmail: string): Promise<void> => {
await apiClient.post('/api/auth/email/change/', { new_email: newEmail });
await apiClient.post('/auth/email/change/', { new_email: newEmail });
};
export const confirmEmailChange = async (token: string): Promise<void> => {
await apiClient.post('/api/auth/email/change/confirm/', { token });
await apiClient.post('/auth/email/change/confirm/', { token });
};
// Password API
@@ -115,7 +115,7 @@ export const changePassword = async (
currentPassword: string,
newPassword: string
): Promise<void> => {
await apiClient.post('/api/auth/password/change/', {
await apiClient.post('/auth/password/change/', {
current_password: currentPassword,
new_password: newPassword,
});
@@ -123,12 +123,12 @@ export const changePassword = async (
// 2FA API (using new MFA endpoints)
export const setupTOTP = async (): Promise<TOTPSetupResponse> => {
const response = await apiClient.post('/api/auth/mfa/totp/setup/');
const response = await apiClient.post('/auth/mfa/totp/setup/');
return response.data;
};
export const verifyTOTP = async (code: string): Promise<TOTPVerifyResponse> => {
const response = await apiClient.post('/api/auth/mfa/totp/verify/', { code });
const response = await apiClient.post('/auth/mfa/totp/verify/', { code });
// Map response to expected format
return {
success: response.data.success,
@@ -137,46 +137,46 @@ export const verifyTOTP = async (code: string): Promise<TOTPVerifyResponse> => {
};
export const disableTOTP = async (code: string): Promise<void> => {
await apiClient.post('/api/auth/mfa/disable/', { mfa_code: code });
await apiClient.post('/auth/mfa/disable/', { mfa_code: code });
};
export const getRecoveryCodes = async (): Promise<string[]> => {
const response = await apiClient.get('/api/auth/mfa/backup-codes/status/');
const response = await apiClient.get('/auth/mfa/backup-codes/status/');
// Note: Actual codes are only shown when generated, not retrievable later
return [];
};
export const regenerateRecoveryCodes = async (): Promise<string[]> => {
const response = await apiClient.post('/api/auth/mfa/backup-codes/');
const response = await apiClient.post('/auth/mfa/backup-codes/');
return response.data.backup_codes;
};
// Sessions API
export const getSessions = async (): Promise<Session[]> => {
const response = await apiClient.get('/api/auth/sessions/');
const response = await apiClient.get('/auth/sessions/');
return response.data;
};
export const revokeSession = async (sessionId: string): Promise<void> => {
await apiClient.delete(`/api/auth/sessions/${sessionId}/`);
await apiClient.delete(`/auth/sessions/${sessionId}/`);
};
export const revokeOtherSessions = async (): Promise<void> => {
await apiClient.post('/api/auth/sessions/revoke-others/');
await apiClient.post('/auth/sessions/revoke-others/');
};
export const getLoginHistory = async (): Promise<LoginHistoryEntry[]> => {
const response = await apiClient.get('/api/auth/login-history/');
const response = await apiClient.get('/auth/login-history/');
return response.data;
};
// Phone Verification API
export const sendPhoneVerification = async (phone: string): Promise<void> => {
await apiClient.post('/api/auth/phone/verify/send/', { phone });
await apiClient.post('/auth/phone/verify/send/', { phone });
};
export const verifyPhoneCode = async (code: string): Promise<void> => {
await apiClient.post('/api/auth/phone/verify/confirm/', { code });
await apiClient.post('/auth/phone/verify/confirm/', { code });
};
// Multiple Email Management API
@@ -189,27 +189,27 @@ export interface UserEmail {
}
export const getUserEmails = async (): Promise<UserEmail[]> => {
const response = await apiClient.get('/api/auth/emails/');
const response = await apiClient.get('/auth/emails/');
return response.data;
};
export const addUserEmail = async (email: string): Promise<UserEmail> => {
const response = await apiClient.post('/api/auth/emails/', { email });
const response = await apiClient.post('/auth/emails/', { email });
return response.data;
};
export const deleteUserEmail = async (emailId: number): Promise<void> => {
await apiClient.delete(`/api/auth/emails/${emailId}/`);
await apiClient.delete(`/auth/emails/${emailId}/`);
};
export const sendUserEmailVerification = async (emailId: number): Promise<void> => {
await apiClient.post(`/api/auth/emails/${emailId}/send-verification/`);
await apiClient.post(`/auth/emails/${emailId}/send-verification/`);
};
export const verifyUserEmail = async (emailId: number, token: string): Promise<void> => {
await apiClient.post(`/api/auth/emails/${emailId}/verify/`, { token });
await apiClient.post(`/auth/emails/${emailId}/verify/`, { token });
};
export const setPrimaryEmail = async (emailId: number): Promise<void> => {
await apiClient.post(`/api/auth/emails/${emailId}/set-primary/`);
await apiClient.post(`/auth/emails/${emailId}/set-primary/`);
};

View File

@@ -122,7 +122,7 @@ export interface IncomingTicketEmail {
* Get ticket email settings
*/
export const getTicketEmailSettings = async (): Promise<TicketEmailSettings> => {
const response = await apiClient.get('/api/tickets/email-settings/');
const response = await apiClient.get('/tickets/email-settings/');
return response.data;
};
@@ -132,7 +132,7 @@ export const getTicketEmailSettings = async (): Promise<TicketEmailSettings> =>
export const updateTicketEmailSettings = async (
data: TicketEmailSettingsUpdate
): Promise<TicketEmailSettings> => {
const response = await apiClient.patch('/api/tickets/email-settings/', data);
const response = await apiClient.patch('/tickets/email-settings/', data);
return response.data;
};
@@ -140,7 +140,7 @@ export const updateTicketEmailSettings = async (
* Test IMAP connection
*/
export const testImapConnection = async (): Promise<TestConnectionResult> => {
const response = await apiClient.post('/api/tickets/email-settings/test-imap/');
const response = await apiClient.post('/tickets/email-settings/test-imap/');
return response.data;
};
@@ -148,7 +148,7 @@ export const testImapConnection = async (): Promise<TestConnectionResult> => {
* Test SMTP connection
*/
export const testSmtpConnection = async (): Promise<TestConnectionResult> => {
const response = await apiClient.post('/api/tickets/email-settings/test-smtp/');
const response = await apiClient.post('/tickets/email-settings/test-smtp/');
return response.data;
};
@@ -159,7 +159,7 @@ export const testEmailConnection = testImapConnection;
* Manually trigger email fetch
*/
export const fetchEmailsNow = async (): Promise<FetchNowResult> => {
const response = await apiClient.post('/api/tickets/email-settings/fetch-now/');
const response = await apiClient.post('/tickets/email-settings/fetch-now/');
return response.data;
};
@@ -170,7 +170,7 @@ export const getIncomingEmails = async (params?: {
status?: string;
ticket?: number;
}): Promise<IncomingTicketEmail[]> => {
const response = await apiClient.get('/api/tickets/incoming-emails/', { params });
const response = await apiClient.get('/tickets/incoming-emails/', { params });
return response.data;
};
@@ -183,7 +183,7 @@ export const reprocessIncomingEmail = async (id: number): Promise<{
comment_id?: number;
ticket_id?: number;
}> => {
const response = await apiClient.post(`/api/tickets/incoming-emails/${id}/reprocess/`);
const response = await apiClient.post(`/tickets/incoming-emails/${id}/reprocess/`);
return response.data;
};
@@ -193,7 +193,7 @@ export const reprocessIncomingEmail = async (id: number): Promise<{
* 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('/api/tickets/email-settings/detect/', { email });
const response = await apiClient.post('/tickets/email-settings/detect/', { email });
return response.data;
};
@@ -225,7 +225,7 @@ export interface OAuthCredential {
* Get OAuth configuration status
*/
export const getOAuthStatus = async (): Promise<OAuthStatusResult> => {
const response = await apiClient.get('/api/oauth/status/');
const response = await apiClient.get('/oauth/status/');
return response.data;
};
@@ -233,7 +233,7 @@ export const getOAuthStatus = async (): Promise<OAuthStatusResult> => {
* Initiate Google OAuth flow
*/
export const initiateGoogleOAuth = async (purpose: string = 'email'): Promise<OAuthInitiateResult> => {
const response = await apiClient.post('/api/oauth/google/initiate/', { purpose });
const response = await apiClient.post('/oauth/google/initiate/', { purpose });
return response.data;
};
@@ -241,7 +241,7 @@ export const initiateGoogleOAuth = async (purpose: string = 'email'): Promise<OA
* Initiate Microsoft OAuth flow
*/
export const initiateMicrosoftOAuth = async (purpose: string = 'email'): Promise<OAuthInitiateResult> => {
const response = await apiClient.post('/api/oauth/microsoft/initiate/', { purpose });
const response = await apiClient.post('/oauth/microsoft/initiate/', { purpose });
return response.data;
};
@@ -249,7 +249,7 @@ export const initiateMicrosoftOAuth = async (purpose: string = 'email'): Promise
* List OAuth credentials
*/
export const getOAuthCredentials = async (): Promise<OAuthCredential[]> => {
const response = await apiClient.get('/api/oauth/credentials/');
const response = await apiClient.get('/oauth/credentials/');
return response.data;
};
@@ -257,6 +257,6 @@ export const getOAuthCredentials = async (): Promise<OAuthCredential[]> => {
* Delete OAuth credential
*/
export const deleteOAuthCredential = async (id: number): Promise<{ success: boolean; message: string }> => {
const response = await apiClient.delete(`/api/oauth/credentials/${id}/`);
const response = await apiClient.delete(`/oauth/credentials/${id}/`);
return response.data;
};

View File

@@ -17,52 +17,52 @@ export const getTickets = async (filters?: TicketFilters): Promise<Ticket[]> =>
if (filters?.ticketType) params.append('ticket_type', filters.ticketType);
if (filters?.assignee) params.append('assignee', filters.assignee);
const response = await apiClient.get(`/api/tickets/${params.toString() ? `?${params.toString()}` : ''}`);
const response = await apiClient.get(`/tickets/${params.toString() ? `?${params.toString()}` : ''}`);
return response.data;
};
export const getTicket = async (id: string): Promise<Ticket> => {
const response = await apiClient.get(`/api/tickets/${id}/`);
const response = await apiClient.get(`/tickets/${id}/`);
return response.data;
};
export const createTicket = async (data: Partial<Ticket>): Promise<Ticket> => {
const response = await apiClient.post('/api/tickets/', data);
const response = await apiClient.post('/tickets/', data);
return response.data;
};
export const updateTicket = async (id: string, data: Partial<Ticket>): Promise<Ticket> => {
const response = await apiClient.patch(`/api/tickets/${id}/`, data);
const response = await apiClient.patch(`/tickets/${id}/`, data);
return response.data;
};
export const deleteTicket = async (id: string): Promise<void> => {
await apiClient.delete(`/api/tickets/${id}/`);
await apiClient.delete(`/tickets/${id}/`);
};
export const getTicketComments = async (ticketId: string): Promise<TicketComment[]> => {
const response = await apiClient.get(`/api/tickets/${ticketId}/comments/`);
const response = await apiClient.get(`/tickets/${ticketId}/comments/`);
return response.data;
};
export const createTicketComment = async (ticketId: string, data: Partial<TicketComment>): Promise<TicketComment> => {
const response = await apiClient.post(`/api/tickets/${ticketId}/comments/`, data);
const response = await apiClient.post(`/tickets/${ticketId}/comments/`, data);
return response.data;
};
// Ticket Templates
export const getTicketTemplates = async (): Promise<TicketTemplate[]> => {
const response = await apiClient.get('/api/tickets/templates/');
const response = await apiClient.get('/tickets/templates/');
return response.data;
};
export const getTicketTemplate = async (id: string): Promise<TicketTemplate> => {
const response = await apiClient.get(`/api/tickets/templates/${id}/`);
const response = await apiClient.get(`/tickets/templates/${id}/`);
return response.data;
};
// Canned Responses
export const getCannedResponses = async (): Promise<CannedResponse[]> => {
const response = await apiClient.get('/api/tickets/canned-responses/');
const response = await apiClient.get('/tickets/canned-responses/');
return response.data;
};