Add subcription feature

This commit is contained in:
Urtzi Alfaro
2026-01-13 22:22:38 +01:00
parent b931a5c45e
commit 6ddf608d37
61 changed files with 7915 additions and 1238 deletions

View File

@@ -13,6 +13,7 @@ import {
TenantSearchParams,
TenantNearbyParams,
AddMemberWithUserCreate,
BakeryRegistrationWithSubscription,
} from '../types/tenant';
import { ApiError } from '../client';
@@ -170,6 +171,24 @@ export const useRegisterBakery = (
});
};
export const useRegisterBakeryWithSubscription = (
options?: UseMutationOptions<TenantResponse, ApiError, BakeryRegistrationWithSubscription>
) => {
const queryClient = useQueryClient();
return useMutation<TenantResponse, ApiError, BakeryRegistrationWithSubscription>({
mutationFn: (bakeryData: BakeryRegistrationWithSubscription) => tenantService.registerBakeryWithSubscription(bakeryData),
onSuccess: (data, variables) => {
// Invalidate user tenants to include the new one
queryClient.invalidateQueries({ queryKey: tenantKeys.userTenants('') });
queryClient.invalidateQueries({ queryKey: tenantKeys.userOwnedTenants('') });
// Set the tenant data in cache
queryClient.setQueryData(tenantKeys.detail(data.id), data);
},
...options,
});
};
export const useUpdateTenant = (
options?: UseMutationOptions<TenantResponse, ApiError, { tenantId: string; updateData: TenantUpdate }>
) => {

View File

@@ -37,6 +37,10 @@ export class AuthService {
return apiClient.post<TokenResponse>(`${this.baseUrl}/register`, userData);
}
async registerWithSubscription(userData: UserRegistration): Promise<UserRegistrationWithSubscriptionResponse> {
return apiClient.post<UserRegistrationWithSubscriptionResponse>(`${this.baseUrl}/register-with-subscription`, userData);
}
async login(loginData: UserLogin): Promise<TokenResponse> {
return apiClient.post<TokenResponse>(`${this.baseUrl}/login`, loginData);
}

View File

@@ -14,6 +14,7 @@
import { apiClient } from '../client';
import {
BakeryRegistration,
BakeryRegistrationWithSubscription,
TenantResponse,
TenantAccessResponse,
TenantUpdate,
@@ -22,6 +23,7 @@ import {
TenantSearchParams,
TenantNearbyParams,
AddMemberWithUserCreate,
SubscriptionLinkingResponse,
} from '../types/tenant';
export class TenantService {
@@ -35,6 +37,21 @@ export class TenantService {
return apiClient.post<TenantResponse>(`${this.baseUrl}/register`, bakeryData);
}
async registerBakeryWithSubscription(bakeryData: BakeryRegistrationWithSubscription): Promise<TenantResponse> {
return apiClient.post<TenantResponse>(`${this.baseUrl}/register`, bakeryData);
}
async linkSubscriptionToTenant(
tenantId: string,
subscriptionId: string,
userId: string
): Promise<SubscriptionLinkingResponse> {
return apiClient.post<SubscriptionLinkingResponse>(
`${this.baseUrl}/subscriptions/link`,
{ tenant_id: tenantId, subscription_id: subscriptionId, user_id: userId }
);
}
async getTenant(tenantId: string): Promise<TenantResponse> {
return apiClient.get<TenantResponse>(`${this.baseUrl}/${tenantId}`);
}

View File

@@ -1,4 +1,30 @@
// frontend/src/api/types/auth.ts
// ================================================================
/**
* Authentication Type Definitions
*
* Aligned with backend schemas:
* - services/auth/app/schemas/auth.py
* - services/auth/app/schemas/users.py
*
* Last Updated: 2025-10-05
* Status: ✅ Complete - Zero drift with backend
*/
=======
// ================================================================
// frontend/src/api/types/auth.ts
// ================================================================
/**
* Authentication Type Definitions
*
* Aligned with backend schemas:
* - services/auth/app/schemas/auth.py
* - services/auth/app/schemas/users.py
*
* Last Updated: 2025-10-13
* Status: ✅ Complete - Zero drift with backend
* Changes: Removed use_trial, added payment_customer_id and default_payment_method_id
*/================================================================
// frontend/src/api/types/auth.ts
// ================================================================
/**
@@ -27,7 +53,7 @@ export interface UserRegistration {
tenant_name?: string | null; // max_length=255
role?: string | null; // Default: "admin", pattern: ^(user|admin|manager|super_admin)$
subscription_plan?: string | null; // Default: "starter", options: starter, professional, enterprise
use_trial?: boolean | null; // Default: false - Whether to use trial period
billing_cycle?: 'monthly' | 'yearly' | null; // Default: "monthly" - Billing cycle preference
payment_method_id?: string | null; // Stripe payment method ID
coupon_code?: string | null; // Promotional coupon code for discounts/trial extensions
// GDPR Consent fields
@@ -35,6 +61,20 @@ export interface UserRegistration {
privacy_accepted?: boolean; // Default: true - Accept privacy policy
marketing_consent?: boolean; // Default: false - Consent to marketing communications
analytics_consent?: boolean; // Default: false - Consent to analytics cookies
// NEW: Billing address fields for subscription creation
address?: string | null; // Billing address
postal_code?: string | null; // Billing postal code
city?: string | null; // Billing city
country?: string | null; // Billing country
}
/**
* User registration with subscription response
* Extended token response for registration with subscription
* Backend: services/auth/app/schemas/auth.py:70-80 (TokenResponse with subscription_id)
*/
export interface UserRegistrationWithSubscriptionResponse extends TokenResponse {
subscription_id?: string | null; // ID of the created subscription (returned if subscription was created during registration)
}
/**
@@ -165,6 +205,8 @@ export interface UserResponse {
timezone?: string | null;
tenant_id?: string | null;
role?: string | null; // Default: "admin"
payment_customer_id?: string | null; // Payment provider customer ID (Stripe, etc.)
default_payment_method_id?: string | null; // Default payment method ID
}
/**

View File

@@ -255,3 +255,38 @@ export interface TenantNearbyParams {
radius_km?: number;
limit?: number;
}
// ================================================================
// NEW ARCHITECTURE: TENANT-INDEPENDENT SUBSCRIPTION TYPES
// ================================================================
/**
* Subscription linking request for new registration flow
* Backend: services/tenant/app/api/tenant_operations.py
*/
export interface SubscriptionLinkingRequest {
tenant_id: string; // Tenant ID to link subscription to
subscription_id: string; // Subscription ID to link
user_id: string; // User ID performing the linking
}
/**
* Subscription linking response
*/
export interface SubscriptionLinkingResponse {
success: boolean;
message: string;
data?: {
tenant_id: string;
subscription_id: string;
status: string;
};
}
/**
* Extended BakeryRegistration with subscription linking support
*/
export interface BakeryRegistrationWithSubscription extends BakeryRegistration {
subscription_id?: string | null; // Optional subscription ID to link
link_existing_subscription?: boolean | null; // Flag to link existing subscription
}