2026-05-08 19:59:43 +03:00
|
|
|
import { apiClient, ensureCsrfCookie } from './client';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* API-вызовы для AuthController (см. app/Http/Controllers/Api/AuthController.php).
|
|
|
|
|
*
|
|
|
|
|
* Все методы делают `ensureCsrfCookie()` перед POST'ами — Sanctum SPA flow.
|
|
|
|
|
*/
|
|
|
|
|
|
2026-05-09 11:41:35 +03:00
|
|
|
export type NotificationChannel = 'inapp' | 'push' | 'email';
|
|
|
|
|
export type NotificationEventKey =
|
|
|
|
|
| 'new_lead'
|
|
|
|
|
| 'reminder'
|
|
|
|
|
| 'low_balance'
|
|
|
|
|
| 'zero_balance'
|
|
|
|
|
| 'topup_success'
|
|
|
|
|
| 'invoice_paid'
|
|
|
|
|
| 'new_device_login'
|
|
|
|
|
| 'marketing';
|
|
|
|
|
export type NotificationPreferences = Partial<
|
|
|
|
|
Record<NotificationEventKey, Partial<Record<NotificationChannel, boolean>>>
|
|
|
|
|
>;
|
|
|
|
|
|
2026-05-08 19:59:43 +03:00
|
|
|
export interface AuthUser {
|
|
|
|
|
id: number;
|
|
|
|
|
email: string;
|
|
|
|
|
first_name: string | null;
|
|
|
|
|
last_name: string | null;
|
|
|
|
|
tenant_id: number;
|
|
|
|
|
totp_enabled: boolean;
|
|
|
|
|
last_login_at: string | null;
|
2026-05-09 11:41:35 +03:00
|
|
|
notification_preferences?: NotificationPreferences;
|
|
|
|
|
sound_enabled?: boolean;
|
2026-05-08 19:59:43 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoginPayload {
|
|
|
|
|
email: string;
|
|
|
|
|
password: string;
|
|
|
|
|
remember?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoginResponse {
|
|
|
|
|
user: AuthUser;
|
|
|
|
|
requires_2fa: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface RegisterPayload {
|
|
|
|
|
email: string;
|
|
|
|
|
password: string;
|
|
|
|
|
accept_offer: boolean;
|
|
|
|
|
accept_pdn: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function login(payload: LoginPayload): Promise<LoginResponse> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<LoginResponse>('/api/auth/login', payload);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function register(payload: RegisterPayload): Promise<LoginResponse> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<LoginResponse>('/api/auth/register', payload);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function me(): Promise<AuthUser> {
|
|
|
|
|
const { data } = await apiClient.get<{ user: AuthUser }>('/api/auth/me');
|
|
|
|
|
return data.user;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function logout(): Promise<void> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
await apiClient.post('/api/auth/logout');
|
|
|
|
|
}
|
2026-05-08 20:14:33 +03:00
|
|
|
|
|
|
|
|
export async function verifyTwoFactor(code: string): Promise<LoginResponse> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<LoginResponse>('/api/auth/2fa/verify', { code });
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2026-05-08 21:10:28 +03:00
|
|
|
|
2026-05-09 03:43:58 +03:00
|
|
|
export interface RecoveryCodeResponse extends LoginResponse {
|
|
|
|
|
recovery_codes_remaining: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function useRecoveryCode(code: string): Promise<RecoveryCodeResponse> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<RecoveryCodeResponse>('/api/auth/2fa/recovery-use', { code });
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-09 04:03:02 +03:00
|
|
|
export interface TwoFactorInitResponse {
|
|
|
|
|
secret: string;
|
|
|
|
|
qr_url: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function twoFactorInit(): Promise<TwoFactorInitResponse> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<TwoFactorInitResponse>('/api/2fa/init');
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function twoFactorConfirm(code: string): Promise<{ recovery_codes: string[]; message: string }> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<{ recovery_codes: string[]; message: string }>('/api/2fa/confirm', { code });
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function twoFactorDisable(password: string): Promise<{ message: string }> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<{ message: string }>('/api/2fa/disable', { password });
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function twoFactorRegenerateRecoveryCodes(
|
|
|
|
|
password: string,
|
|
|
|
|
): Promise<{ recovery_codes: string[]; message: string }> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<{ recovery_codes: string[]; message: string }>(
|
|
|
|
|
'/api/2fa/regenerate-recovery-codes',
|
|
|
|
|
{ password },
|
|
|
|
|
);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-08 21:10:28 +03:00
|
|
|
export async function forgotPassword(email: string): Promise<{ message: string }> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<{ message: string }>('/api/auth/forgot', { email });
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2026-05-09 03:36:27 +03:00
|
|
|
|
|
|
|
|
export interface ResetPasswordPayload {
|
|
|
|
|
token: string;
|
|
|
|
|
email: string;
|
|
|
|
|
password: string;
|
|
|
|
|
password_confirmation: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function resetPassword(payload: ResetPasswordPayload): Promise<{ message: string }> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.post<{ message: string }>('/api/auth/reset-password', payload);
|
|
|
|
|
return data;
|
|
|
|
|
}
|
2026-05-09 11:41:35 +03:00
|
|
|
|
|
|
|
|
export interface UpdateNotificationPreferencesPayload {
|
|
|
|
|
prefs: NotificationPreferences;
|
|
|
|
|
sound_enabled?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function updateNotificationPreferences(payload: UpdateNotificationPreferencesPayload): Promise<AuthUser> {
|
|
|
|
|
await ensureCsrfCookie();
|
|
|
|
|
const { data } = await apiClient.patch<{ user: AuthUser }>('/api/auth/me/notification-preferences', payload);
|
|
|
|
|
return data.user;
|
|
|
|
|
}
|