Add order page with real API calls

This commit is contained in:
Urtzi Alfaro
2025-09-19 11:44:38 +02:00
parent 447e2a5012
commit 105410c9d3
22 changed files with 2556 additions and 463 deletions

View File

@@ -25,6 +25,9 @@ class ApiClient {
private tenantId: string | null = null;
private refreshToken: string | null = null;
private isRefreshing: boolean = false;
private refreshAttempts: number = 0;
private maxRefreshAttempts: number = 3;
private lastRefreshAttempt: number = 0;
private failedQueue: Array<{
resolve: (value?: any) => void;
reject: (error?: any) => void;
@@ -72,6 +75,14 @@ class ApiClient {
// Check if error is 401 and we have a refresh token
if (error.response?.status === 401 && this.refreshToken && !originalRequest._retry) {
// Check if we've exceeded max refresh attempts in a short time
const now = Date.now();
if (this.refreshAttempts >= this.maxRefreshAttempts && (now - this.lastRefreshAttempt) < 30000) {
console.log('Max refresh attempts exceeded, logging out');
await this.handleAuthFailure();
return Promise.reject(this.handleError(error));
}
if (this.isRefreshing) {
// If already refreshing, queue this request
return new Promise((resolve, reject) => {
@@ -81,8 +92,12 @@ class ApiClient {
originalRequest._retry = true;
this.isRefreshing = true;
this.refreshAttempts++;
this.lastRefreshAttempt = now;
try {
console.log(`Attempting token refresh (attempt ${this.refreshAttempts})...`);
// Attempt to refresh the token
const response = await this.client.post('/auth/refresh', {
refresh_token: this.refreshToken
@@ -90,6 +105,11 @@ class ApiClient {
const { access_token, refresh_token } = response.data;
console.log('Token refresh successful');
// Reset refresh attempts on success
this.refreshAttempts = 0;
// Update tokens
this.setAuthToken(access_token);
if (refresh_token) {
@@ -107,6 +127,7 @@ class ApiClient {
return this.client(originalRequest);
} catch (refreshError) {
console.error(`Token refresh failed (attempt ${this.refreshAttempts}):`, refreshError);
// Refresh failed, clear tokens and redirect to login
this.processQueue(refreshError, null);
await this.handleAuthFailure();
@@ -165,13 +186,14 @@ class ApiClient {
try {
// Dynamically import to avoid circular dependency
const { useAuthStore } = await import('../../stores/auth.store');
const store = useAuthStore.getState();
const setState = useAuthStore.setState;
// Update the store with new tokens
store.token = accessToken;
if (refreshToken) {
store.refreshToken = refreshToken;
}
setState(state => ({
...state,
token: accessToken,
refreshToken: refreshToken || state.refreshToken,
}));
} catch (error) {
console.warn('Failed to update auth store:', error);
}

View File

@@ -3,18 +3,86 @@
* Based on backend schemas in services/orders/app/schemas/order_schemas.py
*/
export type CustomerType = 'individual' | 'business' | 'central_bakery';
export type DeliveryMethod = 'delivery' | 'pickup';
export type PaymentTerms = 'immediate' | 'net_30' | 'net_60';
export type PaymentMethod = 'cash' | 'card' | 'bank_transfer' | 'account';
export type PaymentStatus = 'pending' | 'partial' | 'paid' | 'failed' | 'refunded';
export type CustomerSegment = 'vip' | 'regular' | 'wholesale';
export type PriorityLevel = 'high' | 'normal' | 'low';
export type OrderType = 'standard' | 'rush' | 'recurring' | 'special';
export type OrderStatus = 'pending' | 'confirmed' | 'in_production' | 'ready' | 'out_for_delivery' | 'delivered' | 'cancelled' | 'failed';
export type OrderSource = 'manual' | 'online' | 'phone' | 'app' | 'api';
export type SalesChannel = 'direct' | 'wholesale' | 'retail';
export type BusinessModel = 'individual_bakery' | 'central_bakery';
export enum CustomerType {
INDIVIDUAL = 'individual',
BUSINESS = 'business',
CENTRAL_BAKERY = 'central_bakery'
}
export enum DeliveryMethod {
DELIVERY = 'delivery',
PICKUP = 'pickup'
}
export enum PaymentTerms {
IMMEDIATE = 'immediate',
NET_30 = 'net_30',
NET_60 = 'net_60'
}
export enum PaymentMethod {
CASH = 'cash',
CARD = 'card',
BANK_TRANSFER = 'bank_transfer',
ACCOUNT = 'account'
}
export enum PaymentStatus {
PENDING = 'pending',
PARTIAL = 'partial',
PAID = 'paid',
FAILED = 'failed',
REFUNDED = 'refunded'
}
export enum CustomerSegment {
VIP = 'vip',
REGULAR = 'regular',
WHOLESALE = 'wholesale'
}
export enum PriorityLevel {
HIGH = 'high',
NORMAL = 'normal',
LOW = 'low'
}
export enum OrderType {
STANDARD = 'standard',
RUSH = 'rush',
RECURRING = 'recurring',
SPECIAL = 'special'
}
export enum OrderStatus {
PENDING = 'pending',
CONFIRMED = 'confirmed',
IN_PRODUCTION = 'in_production',
READY = 'ready',
OUT_FOR_DELIVERY = 'out_for_delivery',
DELIVERED = 'delivered',
CANCELLED = 'cancelled',
FAILED = 'failed'
}
export enum OrderSource {
MANUAL = 'manual',
ONLINE = 'online',
PHONE = 'phone',
APP = 'app',
API = 'api'
}
export enum SalesChannel {
DIRECT = 'direct',
WHOLESALE = 'wholesale',
RETAIL = 'retail'
}
export enum BusinessModel {
INDIVIDUAL_BAKERY = 'individual_bakery',
CENTRAL_BAKERY = 'central_bakery'
}
// ===== Customer Types =====