Improve the frontend modals
This commit is contained in:
@@ -77,16 +77,16 @@ export class AuthService {
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// ATOMIC: User Profile
|
||||
// Backend: services/auth/app/api/users.py
|
||||
// User Profile (authenticated)
|
||||
// Backend: services/auth/app/api/auth_operations.py
|
||||
// ===================================================================
|
||||
|
||||
async getProfile(): Promise<UserResponse> {
|
||||
return apiClient.get<UserResponse>('/users/me');
|
||||
return apiClient.get<UserResponse>(`${this.baseUrl}/me`);
|
||||
}
|
||||
|
||||
async updateProfile(updateData: UserUpdate): Promise<UserResponse> {
|
||||
return apiClient.put<UserResponse>('/users/me', updateData);
|
||||
return apiClient.put<UserResponse>(`${this.baseUrl}/me`, updateData);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
@@ -104,6 +104,106 @@ export class AuthService {
|
||||
});
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Account Management (self-service)
|
||||
// Backend: services/auth/app/api/account_deletion.py
|
||||
// ===================================================================
|
||||
|
||||
async deleteAccount(confirmEmail: string, password: string, reason?: string): Promise<{ message: string; deletion_date: string }> {
|
||||
return apiClient.delete(`${this.baseUrl}/me/account`, {
|
||||
data: {
|
||||
confirm_email: confirmEmail,
|
||||
password: password,
|
||||
reason: reason || ''
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async getAccountDeletionInfo(): Promise<any> {
|
||||
return apiClient.get(`${this.baseUrl}/me/account/deletion-info`);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// GDPR Consent Management
|
||||
// Backend: services/auth/app/api/consent.py
|
||||
// ===================================================================
|
||||
|
||||
async recordConsent(consentData: {
|
||||
terms_accepted: boolean;
|
||||
privacy_accepted: boolean;
|
||||
marketing_consent?: boolean;
|
||||
analytics_consent?: boolean;
|
||||
consent_method: string;
|
||||
consent_version?: string;
|
||||
}): Promise<any> {
|
||||
return apiClient.post(`${this.baseUrl}/me/consent`, consentData);
|
||||
}
|
||||
|
||||
async getCurrentConsent(): Promise<any> {
|
||||
return apiClient.get(`${this.baseUrl}/me/consent/current`);
|
||||
}
|
||||
|
||||
async getConsentHistory(): Promise<any[]> {
|
||||
return apiClient.get(`${this.baseUrl}/me/consent/history`);
|
||||
}
|
||||
|
||||
async updateConsent(consentData: {
|
||||
terms_accepted: boolean;
|
||||
privacy_accepted: boolean;
|
||||
marketing_consent?: boolean;
|
||||
analytics_consent?: boolean;
|
||||
consent_method: string;
|
||||
consent_version?: string;
|
||||
}): Promise<any> {
|
||||
return apiClient.put(`${this.baseUrl}/me/consent`, consentData);
|
||||
}
|
||||
|
||||
async withdrawConsent(): Promise<{ message: string; withdrawn_count: number }> {
|
||||
return apiClient.post(`${this.baseUrl}/me/consent/withdraw`);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Data Export (GDPR)
|
||||
// Backend: services/auth/app/api/data_export.py
|
||||
// ===================================================================
|
||||
|
||||
async exportMyData(): Promise<any> {
|
||||
return apiClient.get(`${this.baseUrl}/me/export`);
|
||||
}
|
||||
|
||||
async getExportSummary(): Promise<any> {
|
||||
return apiClient.get(`${this.baseUrl}/me/export/summary`);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Onboarding Progress
|
||||
// Backend: services/auth/app/api/onboarding_progress.py
|
||||
// ===================================================================
|
||||
|
||||
async getOnboardingProgress(): Promise<any> {
|
||||
return apiClient.get(`${this.baseUrl}/me/onboarding/progress`);
|
||||
}
|
||||
|
||||
async updateOnboardingStep(stepName: string, completed: boolean, data?: any): Promise<any> {
|
||||
return apiClient.put(`${this.baseUrl}/me/onboarding/step`, {
|
||||
step_name: stepName,
|
||||
completed: completed,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
async getNextOnboardingStep(): Promise<{ step: string }> {
|
||||
return apiClient.get(`${this.baseUrl}/me/onboarding/next-step`);
|
||||
}
|
||||
|
||||
async canAccessOnboardingStep(stepName: string): Promise<{ can_access: boolean }> {
|
||||
return apiClient.get(`${this.baseUrl}/me/onboarding/can-access/${stepName}`);
|
||||
}
|
||||
|
||||
async completeOnboarding(): Promise<{ success: boolean; message: string }> {
|
||||
return apiClient.post(`${this.baseUrl}/me/onboarding/complete`);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Health Check
|
||||
// ===================================================================
|
||||
|
||||
@@ -82,9 +82,10 @@ export class OrdersService {
|
||||
* Create a new customer order
|
||||
* POST /tenants/{tenant_id}/orders
|
||||
*/
|
||||
static async createOrder(orderData: OrderCreate): Promise<OrderResponse> {
|
||||
const { tenant_id, ...data } = orderData;
|
||||
return apiClient.post<OrderResponse>(`/tenants/${tenant_id}/orders`, data);
|
||||
static async createOrder(orderData: OrderCreate): Promise<OrderResponse> {
|
||||
const { tenant_id } = orderData;
|
||||
// Note: tenant_id is in both URL path and request body (backend schema requirement)
|
||||
return apiClient.post<OrderResponse>(`/tenants/${tenant_id}/orders`, orderData);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,11 +145,11 @@ export class OrdersService {
|
||||
|
||||
/**
|
||||
* Create a new customer
|
||||
* POST /tenants/{tenant_id}/customers
|
||||
* POST /tenants/{tenant_id}/orders/customers
|
||||
*/
|
||||
static async createCustomer(customerData: CustomerCreate): Promise<CustomerResponse> {
|
||||
const { tenant_id, ...data } = customerData;
|
||||
return apiClient.post<CustomerResponse>(`/tenants/${tenant_id}/customers`, data);
|
||||
return apiClient.post<CustomerResponse>(`/tenants/${tenant_id}/orders/customers`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -413,4 +414,4 @@ export class OrdersService {
|
||||
|
||||
}
|
||||
|
||||
export default OrdersService;
|
||||
export default OrdersService;
|
||||
|
||||
@@ -594,4 +594,4 @@ export class POSService {
|
||||
|
||||
// Export singleton instance
|
||||
export const posService = new POSService();
|
||||
export default posService;
|
||||
export default posService;
|
||||
|
||||
@@ -24,6 +24,7 @@ import type {
|
||||
RecipeCategoriesResponse,
|
||||
RecipeQualityConfiguration,
|
||||
RecipeQualityConfigurationUpdate,
|
||||
RecipeDeletionSummary,
|
||||
} from '../types/recipes';
|
||||
|
||||
export class RecipesService {
|
||||
@@ -94,6 +95,22 @@ export class RecipesService {
|
||||
return apiClient.delete<{ message: string }>(`${this.baseUrl}/${tenantId}/recipes/${recipeId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Archive a recipe (soft delete by setting status to ARCHIVED)
|
||||
* PATCH /tenants/{tenant_id}/recipes/{recipe_id}/archive
|
||||
*/
|
||||
async archiveRecipe(tenantId: string, recipeId: string): Promise<RecipeResponse> {
|
||||
return apiClient.patch<RecipeResponse>(`${this.baseUrl}/${tenantId}/recipes/${recipeId}/archive`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get deletion summary for a recipe
|
||||
* GET /tenants/{tenant_id}/recipes/{recipe_id}/deletion-summary
|
||||
*/
|
||||
async getRecipeDeletionSummary(tenantId: string, recipeId: string): Promise<RecipeDeletionSummary> {
|
||||
return apiClient.get<RecipeDeletionSummary>(`${this.baseUrl}/${tenantId}/recipes/${recipeId}/deletion-summary`);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// ATOMIC: Quality Configuration CRUD
|
||||
// Backend: services/recipes/app/api/recipe_quality_configs.py
|
||||
|
||||
@@ -187,21 +187,48 @@ export class SubscriptionService {
|
||||
/**
|
||||
* Check if tenant can perform an action within quota limits
|
||||
*/
|
||||
async checkQuotaLimit(
|
||||
async checkQuotaLimit(
|
||||
tenantId: string,
|
||||
quotaType: string,
|
||||
requestedAmount?: number
|
||||
): Promise<QuotaCheckResponse> {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (requestedAmount !== undefined) {
|
||||
queryParams.append('requested_amount', requestedAmount.toString());
|
||||
// Map quotaType to the existing endpoints in tenant_operations.py
|
||||
let endpoint: string;
|
||||
switch (quotaType) {
|
||||
case 'inventory_items':
|
||||
endpoint = 'can-add-product';
|
||||
break;
|
||||
case 'users':
|
||||
endpoint = 'can-add-user';
|
||||
break;
|
||||
case 'locations':
|
||||
endpoint = 'can-add-location';
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unsupported quota type: ${quotaType}`);
|
||||
}
|
||||
|
||||
const url = queryParams.toString()
|
||||
? `${this.baseUrl}/subscriptions/${tenantId}/quotas/${quotaType}/check?${queryParams.toString()}`
|
||||
: `${this.baseUrl}/subscriptions/${tenantId}/quotas/${quotaType}/check`;
|
||||
|
||||
return apiClient.get<QuotaCheckResponse>(url);
|
||||
const url = `${this.baseUrl}/subscriptions/${tenantId}/${endpoint}`;
|
||||
|
||||
// Get the response from the endpoint (returns different format than expected)
|
||||
const response = await apiClient.get<{
|
||||
can_add: boolean;
|
||||
current_count?: number;
|
||||
max_allowed?: number;
|
||||
reason?: string;
|
||||
message?: string;
|
||||
}>(url);
|
||||
|
||||
// Map the response to QuotaCheckResponse format
|
||||
return {
|
||||
allowed: response.can_add,
|
||||
current: response.current_count || 0,
|
||||
limit: response.max_allowed || null,
|
||||
remaining: response.max_allowed !== undefined && response.current_count !== undefined
|
||||
? response.max_allowed - response.current_count
|
||||
: null,
|
||||
message: response.reason || response.message || ''
|
||||
};
|
||||
}
|
||||
|
||||
async validatePlanUpgrade(tenantId: string, planKey: string): Promise<PlanUpgradeValidation> {
|
||||
@@ -348,4 +375,4 @@ export class SubscriptionService {
|
||||
}
|
||||
}
|
||||
|
||||
export const subscriptionService = new SubscriptionService();
|
||||
export const subscriptionService = new SubscriptionService();
|
||||
|
||||
@@ -22,6 +22,7 @@ import type {
|
||||
SupplierApproval,
|
||||
SupplierQueryParams,
|
||||
SupplierStatistics,
|
||||
SupplierDeletionSummary,
|
||||
TopSuppliersResponse,
|
||||
PurchaseOrderCreate,
|
||||
PurchaseOrderUpdate,
|
||||
@@ -53,7 +54,7 @@ class SuppliersService {
|
||||
supplierData: SupplierCreate
|
||||
): Promise<SupplierResponse> {
|
||||
return apiClient.post<SupplierResponse>(
|
||||
`${this.baseUrl}/${tenantId}/suppliers/suppliers`,
|
||||
`${this.baseUrl}/${tenantId}/suppliers`,
|
||||
supplierData
|
||||
);
|
||||
}
|
||||
@@ -74,13 +75,13 @@ class SuppliersService {
|
||||
|
||||
const queryString = params.toString() ? `?${params.toString()}` : '';
|
||||
return apiClient.get<PaginatedResponse<SupplierSummary>>(
|
||||
`${this.baseUrl}/${tenantId}/suppliers/suppliers${queryString}`
|
||||
`${this.baseUrl}/${tenantId}/suppliers${queryString}`
|
||||
);
|
||||
}
|
||||
|
||||
async getSupplier(tenantId: string, supplierId: string): Promise<SupplierResponse> {
|
||||
return apiClient.get<SupplierResponse>(
|
||||
`${this.baseUrl}/${tenantId}/suppliers/suppliers/${supplierId}`
|
||||
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ class SuppliersService {
|
||||
updateData: SupplierUpdate
|
||||
): Promise<SupplierResponse> {
|
||||
return apiClient.put<SupplierResponse>(
|
||||
`${this.baseUrl}/${tenantId}/suppliers/suppliers/${supplierId}`,
|
||||
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}`,
|
||||
updateData
|
||||
);
|
||||
}
|
||||
@@ -100,7 +101,16 @@ class SuppliersService {
|
||||
supplierId: string
|
||||
): Promise<{ message: string }> {
|
||||
return apiClient.delete<{ message: string }>(
|
||||
`${this.baseUrl}/${tenantId}/suppliers/suppliers/${supplierId}`
|
||||
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}`
|
||||
);
|
||||
}
|
||||
|
||||
async hardDeleteSupplier(
|
||||
tenantId: string,
|
||||
supplierId: string
|
||||
): Promise<SupplierDeletionSummary> {
|
||||
return apiClient.delete<SupplierDeletionSummary>(
|
||||
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}/hard`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -113,7 +123,7 @@ class SuppliersService {
|
||||
params.append('is_active', isActive.toString());
|
||||
|
||||
return apiClient.get<Array<{ inventory_product_id: string }>>(
|
||||
`${this.baseUrl}/${tenantId}/suppliers/suppliers/${supplierId}/products?${params.toString()}`
|
||||
`${this.baseUrl}/${tenantId}/suppliers/${supplierId}/products?${params.toString()}`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,10 @@ export class UserService {
|
||||
async getUserById(userId: string): Promise<UserResponse> {
|
||||
return apiClient.get<UserResponse>(`${this.baseUrl}/admin/${userId}`);
|
||||
}
|
||||
|
||||
async getUserActivity(userId: string): Promise<any> {
|
||||
return apiClient.get<any>(`/auth/users/${userId}/activity`);
|
||||
}
|
||||
}
|
||||
|
||||
export const userService = new UserService();
|
||||
export const userService = new UserService();
|
||||
|
||||
Reference in New Issue
Block a user