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:
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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/');
|
||||
};
|
||||
|
||||
@@ -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 || {});
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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/`);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user