This commit includes: - Django backend with multi-tenancy (django-tenants) - React + TypeScript frontend with Vite - Platform administration API with role-based access control - Authentication system with token-based auth - Quick login dev tools for testing different user roles - CORS and CSRF configuration for local development - Docker development environment setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
211 lines
5.8 KiB
TypeScript
211 lines
5.8 KiB
TypeScript
import apiClient from './client';
|
|
|
|
// Types
|
|
export interface UserProfile {
|
|
id: number;
|
|
username: string;
|
|
email: string;
|
|
name: string;
|
|
phone?: string;
|
|
phone_verified: boolean;
|
|
avatar_url?: string;
|
|
email_verified: boolean;
|
|
two_factor_enabled: boolean;
|
|
totp_confirmed: boolean;
|
|
sms_2fa_enabled: boolean;
|
|
timezone: string;
|
|
locale: string;
|
|
notification_preferences: NotificationPreferences;
|
|
role: string;
|
|
business?: number;
|
|
business_name?: string;
|
|
business_subdomain?: string;
|
|
// Address fields
|
|
address_line1?: string;
|
|
address_line2?: string;
|
|
city?: string;
|
|
state?: string;
|
|
postal_code?: string;
|
|
country?: string;
|
|
}
|
|
|
|
export interface NotificationPreferences {
|
|
email: boolean;
|
|
sms: boolean;
|
|
in_app: boolean;
|
|
appointment_reminders: boolean;
|
|
marketing: boolean;
|
|
}
|
|
|
|
export interface TOTPSetupResponse {
|
|
secret: string;
|
|
qr_code: string; // Base64 encoded PNG
|
|
provisioning_uri: string;
|
|
}
|
|
|
|
export interface TOTPVerifyResponse {
|
|
success: boolean;
|
|
recovery_codes: string[];
|
|
}
|
|
|
|
export interface Session {
|
|
id: string;
|
|
device_info: string;
|
|
ip_address: string;
|
|
location: string;
|
|
created_at: string;
|
|
last_activity: string;
|
|
is_current: boolean;
|
|
}
|
|
|
|
export interface LoginHistoryEntry {
|
|
id: string;
|
|
timestamp: string;
|
|
ip_address: string;
|
|
device_info: string;
|
|
location: string;
|
|
success: boolean;
|
|
failure_reason?: string;
|
|
two_factor_method?: string;
|
|
}
|
|
|
|
// Profile API
|
|
export const getProfile = async (): Promise<UserProfile> => {
|
|
const response = await apiClient.get('/api/auth/profile/');
|
|
return response.data;
|
|
};
|
|
|
|
export const updateProfile = async (data: Partial<UserProfile>): Promise<UserProfile> => {
|
|
const response = await apiClient.patch('/api/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, {
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
});
|
|
return response.data;
|
|
};
|
|
|
|
export const deleteAvatar = async (): Promise<void> => {
|
|
await apiClient.delete('/api/auth/profile/avatar/');
|
|
};
|
|
|
|
// Email API
|
|
export const sendVerificationEmail = async (): Promise<void> => {
|
|
await apiClient.post('/api/auth/email/verify/send/');
|
|
};
|
|
|
|
export const verifyEmail = async (token: string): Promise<void> => {
|
|
await apiClient.post('/api/auth/email/verify/confirm/', { token });
|
|
};
|
|
|
|
export const requestEmailChange = async (newEmail: string): Promise<void> => {
|
|
await apiClient.post('/api/auth/email/change/', { new_email: newEmail });
|
|
};
|
|
|
|
export const confirmEmailChange = async (token: string): Promise<void> => {
|
|
await apiClient.post('/api/auth/email/change/confirm/', { token });
|
|
};
|
|
|
|
// Password API
|
|
export const changePassword = async (
|
|
currentPassword: string,
|
|
newPassword: string
|
|
): Promise<void> => {
|
|
await apiClient.post('/api/auth/password/change/', {
|
|
current_password: currentPassword,
|
|
new_password: newPassword,
|
|
});
|
|
};
|
|
|
|
// 2FA API
|
|
export const setupTOTP = async (): Promise<TOTPSetupResponse> => {
|
|
const response = await apiClient.post('/api/auth/2fa/totp/setup/');
|
|
return response.data;
|
|
};
|
|
|
|
export const verifyTOTP = async (code: string): Promise<TOTPVerifyResponse> => {
|
|
const response = await apiClient.post('/api/auth/2fa/totp/verify/', { code });
|
|
return response.data;
|
|
};
|
|
|
|
export const disableTOTP = async (code: string): Promise<void> => {
|
|
await apiClient.post('/api/auth/2fa/totp/disable/', { code });
|
|
};
|
|
|
|
export const getRecoveryCodes = async (): Promise<string[]> => {
|
|
const response = await apiClient.get('/api/auth/2fa/recovery-codes/');
|
|
return response.data.codes;
|
|
};
|
|
|
|
export const regenerateRecoveryCodes = async (): Promise<string[]> => {
|
|
const response = await apiClient.post('/api/auth/2fa/recovery-codes/regenerate/');
|
|
return response.data.codes;
|
|
};
|
|
|
|
// Sessions API
|
|
export const getSessions = async (): Promise<Session[]> => {
|
|
const response = await apiClient.get('/api/auth/sessions/');
|
|
return response.data;
|
|
};
|
|
|
|
export const revokeSession = async (sessionId: string): Promise<void> => {
|
|
await apiClient.delete(`/api/auth/sessions/${sessionId}/`);
|
|
};
|
|
|
|
export const revokeOtherSessions = async (): Promise<void> => {
|
|
await apiClient.post('/api/auth/sessions/revoke-others/');
|
|
};
|
|
|
|
export const getLoginHistory = async (): Promise<LoginHistoryEntry[]> => {
|
|
const response = await apiClient.get('/api/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 });
|
|
};
|
|
|
|
export const verifyPhoneCode = async (code: string): Promise<void> => {
|
|
await apiClient.post('/api/auth/phone/verify/confirm/', { code });
|
|
};
|
|
|
|
// Multiple Email Management API
|
|
export interface UserEmail {
|
|
id: number;
|
|
email: string;
|
|
is_primary: boolean;
|
|
verified: boolean;
|
|
created_at: string;
|
|
}
|
|
|
|
export const getUserEmails = async (): Promise<UserEmail[]> => {
|
|
const response = await apiClient.get('/api/auth/emails/');
|
|
return response.data;
|
|
};
|
|
|
|
export const addUserEmail = async (email: string): Promise<UserEmail> => {
|
|
const response = await apiClient.post('/api/auth/emails/', { email });
|
|
return response.data;
|
|
};
|
|
|
|
export const deleteUserEmail = async (emailId: number): Promise<void> => {
|
|
await apiClient.delete(`/api/auth/emails/${emailId}/`);
|
|
};
|
|
|
|
export const sendUserEmailVerification = async (emailId: number): Promise<void> => {
|
|
await apiClient.post(`/api/auth/emails/${emailId}/send-verification/`);
|
|
};
|
|
|
|
export const verifyUserEmail = async (emailId: number, token: string): Promise<void> => {
|
|
await apiClient.post(`/api/auth/emails/${emailId}/verify/`, { token });
|
|
};
|
|
|
|
export const setPrimaryEmail = async (emailId: number): Promise<void> => {
|
|
await apiClient.post(`/api/auth/emails/${emailId}/set-primary/`);
|
|
};
|