hey-pharmacist-ecommerce 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +107 -1
  2. package/dist/index.d.mts +3636 -316
  3. package/dist/index.d.ts +3636 -316
  4. package/dist/index.js +6802 -3866
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +6756 -3818
  7. package/dist/index.mjs.map +1 -1
  8. package/package.json +17 -14
  9. package/src/components/AddressFormModal.tsx +171 -0
  10. package/src/components/CartItem.tsx +17 -12
  11. package/src/components/FilterChips.tsx +195 -0
  12. package/src/components/Header.tsx +121 -71
  13. package/src/components/OrderCard.tsx +18 -25
  14. package/src/components/ProductCard.tsx +209 -72
  15. package/src/components/ui/Button.tsx +13 -5
  16. package/src/components/ui/Card.tsx +46 -0
  17. package/src/hooks/useAddresses.ts +83 -0
  18. package/src/hooks/useOrders.ts +37 -19
  19. package/src/hooks/useProducts.ts +55 -63
  20. package/src/hooks/useWishlistProducts.ts +75 -0
  21. package/src/index.ts +3 -19
  22. package/src/lib/Apis/api.ts +1 -0
  23. package/src/lib/Apis/apis/cart-api.ts +3 -3
  24. package/src/lib/Apis/apis/inventory-api.ts +0 -108
  25. package/src/lib/Apis/apis/stores-api.ts +70 -0
  26. package/src/lib/Apis/apis/wishlist-api.ts +447 -0
  27. package/src/lib/Apis/models/cart-item-populated.ts +0 -1
  28. package/src/lib/Apis/models/create-single-variant-product-dto.ts +3 -10
  29. package/src/lib/Apis/models/create-variant-dto.ts +26 -33
  30. package/src/lib/Apis/models/extended-product-dto.ts +20 -24
  31. package/src/lib/Apis/models/index.ts +2 -1
  32. package/src/lib/Apis/models/order-time-line-dto.ts +49 -0
  33. package/src/lib/Apis/models/order.ts +3 -8
  34. package/src/lib/Apis/models/populated-order.ts +3 -8
  35. package/src/lib/Apis/models/product-variant.ts +29 -0
  36. package/src/lib/Apis/models/update-product-variant-dto.ts +16 -23
  37. package/src/lib/Apis/models/wishlist.ts +51 -0
  38. package/src/lib/Apis/wrapper.ts +18 -7
  39. package/src/lib/api-adapter/index.ts +0 -12
  40. package/src/lib/types/index.ts +16 -61
  41. package/src/lib/utils/colors.ts +7 -4
  42. package/src/lib/utils/format.ts +1 -1
  43. package/src/lib/validations/address.ts +14 -0
  44. package/src/providers/AuthProvider.tsx +61 -31
  45. package/src/providers/CartProvider.tsx +18 -28
  46. package/src/providers/EcommerceProvider.tsx +7 -0
  47. package/src/providers/FavoritesProvider.tsx +86 -0
  48. package/src/providers/ThemeProvider.tsx +16 -1
  49. package/src/providers/WishlistProvider.tsx +174 -0
  50. package/src/screens/AddressesScreen.tsx +484 -0
  51. package/src/screens/CartScreen.tsx +120 -84
  52. package/src/screens/CategoriesScreen.tsx +120 -0
  53. package/src/screens/CheckoutScreen.tsx +919 -241
  54. package/src/screens/CurrentOrdersScreen.tsx +125 -61
  55. package/src/screens/HomeScreen.tsx +209 -0
  56. package/src/screens/LoginScreen.tsx +133 -88
  57. package/src/screens/NewAddressScreen.tsx +187 -0
  58. package/src/screens/OrdersScreen.tsx +162 -50
  59. package/src/screens/ProductDetailScreen.tsx +641 -190
  60. package/src/screens/ProfileScreen.tsx +192 -116
  61. package/src/screens/RegisterScreen.tsx +193 -144
  62. package/src/screens/SearchResultsScreen.tsx +165 -0
  63. package/src/screens/ShopScreen.tsx +1110 -146
  64. package/src/screens/WishlistScreen.tsx +428 -0
  65. package/src/lib/Apis/models/inventory-paginated-response.ts +0 -75
  66. package/src/lib/api/auth.ts +0 -81
  67. package/src/lib/api/cart.ts +0 -42
  68. package/src/lib/api/orders.ts +0 -53
  69. package/src/lib/api/products.ts +0 -51
  70. package/src/lib/api-adapter/auth-adapter.ts +0 -196
  71. package/src/lib/api-adapter/cart-adapter.ts +0 -193
  72. package/src/lib/api-adapter/mappers.ts +0 -152
  73. package/src/lib/api-adapter/orders-adapter.ts +0 -195
  74. package/src/lib/api-adapter/products-adapter.ts +0 -194
@@ -87,7 +87,6 @@ export * from './google-analytics-response-dto';
87
87
  export * from './group-with-no-users-dto';
88
88
  export * from './group-with-users-dto';
89
89
  export * from './images-upload-body';
90
- export * from './inventory-paginated-response';
91
90
  export * from './link-stats-response-dto';
92
91
  export * from './login-dto';
93
92
  export * from './manual-discount';
@@ -102,6 +101,7 @@ export * from './object-id';
102
101
  export * from './open-api';
103
102
  export * from './order';
104
103
  export * from './order-paginated-response';
104
+ export * from './order-time-line-dto';
105
105
  export * from './orders-insights-dto';
106
106
  export * from './paginated-products-dto';
107
107
  export * from './payment';
@@ -193,5 +193,6 @@ export * from './user-insights-dto';
193
193
  export * from './user-with-no-id';
194
194
  export * from './users-paginated-response';
195
195
  export * from './verify-email-dto';
196
+ export * from './wishlist';
196
197
  export * from './zone';
197
198
  export * from './zone-single-size';
@@ -0,0 +1,49 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Hey Pharamcist API
5
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
6
+ *
7
+ * OpenAPI spec version: 1.0
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by the swagger code generator program.
11
+ * https://github.com/swagger-api/swagger-codegen.git
12
+ * Do not edit the class manually.
13
+ */
14
+ /**
15
+ *
16
+ * @export
17
+ * @interface OrderTimeLineDTO
18
+ */
19
+ export interface OrderTimeLineDTO {
20
+ _id?: string;
21
+ /**
22
+ *
23
+ * @type {string}
24
+ * @memberof OrderTimeLineDTO
25
+ */
26
+ title: string;
27
+ /**
28
+ *
29
+ * @type {Date}
30
+ * @memberof OrderTimeLineDTO
31
+ */
32
+ date: Date;
33
+ /**
34
+ *
35
+ * @type {string}
36
+ * @memberof OrderTimeLineDTO
37
+ */
38
+ type: OrderTimeLineDTOTypeEnum;
39
+ }
40
+
41
+ /**
42
+ * @export
43
+ * @enum {string}
44
+ */
45
+ export enum OrderTimeLineDTOTypeEnum {
46
+ OrderStatus = 'orderStatus',
47
+ Reminder = 'reminder'
48
+ }
49
+
@@ -15,6 +15,7 @@ import { Address } from './address';
15
15
  import { CartItem } from './cart-item';
16
16
  import { Discount } from './discount';
17
17
  import { ObjectId } from './object-id';
18
+ import { OrderTimeLineDTO } from './order-time-line-dto';
18
19
  import { PreferedPickOrDeliveryTimeDto } from './prefered-pick-or-delivery-time-dto';
19
20
  import { ShippingInfo } from './shipping-info';
20
21
  import { UserWithNoId } from './user-with-no-id';
@@ -141,10 +142,10 @@ export interface Order {
141
142
  stringId: string;
142
143
  /**
143
144
  *
144
- * @type {Array<Array>}
145
+ * @type {Array<OrderTimeLineDTO>}
145
146
  * @memberof Order
146
147
  */
147
- orderTimeLine: Array<Array<any>>;
148
+ orderTimeLine: Array<OrderTimeLineDTO>;
148
149
  /**
149
150
  *
150
151
  * @type {UserWithNoId}
@@ -163,12 +164,6 @@ export interface Order {
163
164
  * @memberof Order
164
165
  */
165
166
  pickUpAddress: Address;
166
- /**
167
- *
168
- * @type {Address}
169
- * @memberof Order
170
- */
171
- inventoryAddress: Address;
172
167
  /**
173
168
  *
174
169
  * @type {PreferedPickOrDeliveryTimeDto}
@@ -15,6 +15,7 @@ import { Address } from './address';
15
15
  import { CartItemPopulated } from './cart-item-populated';
16
16
  import { Discount } from './discount';
17
17
  import { ObjectId } from './object-id';
18
+ import { OrderTimeLineDTO } from './order-time-line-dto';
18
19
  import { Payment } from './payment';
19
20
  import { PreferedPickOrDeliveryTimeDto } from './prefered-pick-or-delivery-time-dto';
20
21
  import { ShippingInfo } from './shipping-info';
@@ -130,10 +131,10 @@ export interface PopulatedOrder {
130
131
  stringId?: string;
131
132
  /**
132
133
  *
133
- * @type {Array<Array>}
134
+ * @type {Array<OrderTimeLineDTO>}
134
135
  * @memberof PopulatedOrder
135
136
  */
136
- orderTimeLine?: Array<Array<any>>;
137
+ orderTimeLine?: Array<OrderTimeLineDTO>;
137
138
  /**
138
139
  *
139
140
  * @type {UserWithNoId}
@@ -152,12 +153,6 @@ export interface PopulatedOrder {
152
153
  * @memberof PopulatedOrder
153
154
  */
154
155
  pickUpAddress?: Address;
155
- /**
156
- *
157
- * @type {Address}
158
- * @memberof PopulatedOrder
159
- */
160
- inventoryAddress?: Address;
161
156
  /**
162
157
  *
163
158
  * @type {PreferedPickOrDeliveryTimeDto}
@@ -164,4 +164,33 @@ export interface ProductVariant {
164
164
  * @memberof ProductVariant
165
165
  */
166
166
  tables: Array<TableDto>;
167
+ /**
168
+ *
169
+ * @type {number}
170
+ * @memberof ProductVariant
171
+ */
172
+ inventoryCount: number;
173
+ /**
174
+ *
175
+ * @type {string}
176
+ * @memberof ProductVariant
177
+ */
178
+ inventoryStatus: ProductVariantInventoryStatusEnum;
179
+ /**
180
+ *
181
+ * @type {Date}
182
+ * @memberof ProductVariant
183
+ */
184
+ inventoryLastUpdated: Date;
185
+ }
186
+
187
+ /**
188
+ * @export
189
+ * @enum {string}
190
+ */
191
+ export enum ProductVariantInventoryStatusEnum {
192
+ INSTOCK = 'IN_STOCK',
193
+ OUTOFSTOCK = 'OUT_OF_STOCK',
194
+ LOWSTOCK = 'LOW_STOCK'
167
195
  }
196
+
@@ -12,7 +12,6 @@
12
12
  * Do not edit the class manually.
13
13
  */
14
14
  import { SingleProductMedia } from './single-product-media';
15
- import { TableDto } from './table-dto';
16
15
  /**
17
16
  *
18
17
  * @export
@@ -25,19 +24,31 @@ export interface UpdateProductVariantDto {
25
24
  * @type {string}
26
25
  * @memberof UpdateProductVariantDto
27
26
  */
28
- parentCategory?: string;
27
+ name?: string;
29
28
  /**
30
29
  *
31
- * @type {string}
30
+ * @type {Array<SingleProductMedia>}
32
31
  * @memberof UpdateProductVariantDto
33
32
  */
34
- name?: string;
33
+ productMedia?: Array<SingleProductMedia>;
35
34
  /**
36
35
  *
37
36
  * @type {string}
38
37
  * @memberof UpdateProductVariantDto
39
38
  */
40
39
  description?: string;
40
+ /**
41
+ *
42
+ * @type {{ [key: string]: string; }}
43
+ * @memberof UpdateProductVariantDto
44
+ */
45
+ attribute?: { [key: string]: string; };
46
+ /**
47
+ *
48
+ * @type {number}
49
+ * @memberof UpdateProductVariantDto
50
+ */
51
+ inventory?: number;
41
52
  /**
42
53
  * The width of the product variant in cm
43
54
  * @type {number}
@@ -74,12 +85,6 @@ export interface UpdateProductVariantDto {
74
85
  * @memberof UpdateProductVariantDto
75
86
  */
76
87
  sku?: string;
77
- /**
78
- *
79
- * @type {{ [key: string]: string; }}
80
- * @memberof UpdateProductVariantDto
81
- */
82
- attribute?: { [key: string]: string; };
83
88
  /**
84
89
  *
85
90
  * @type {number}
@@ -98,22 +103,10 @@ export interface UpdateProductVariantDto {
98
103
  * @memberof UpdateProductVariantDto
99
104
  */
100
105
  totalSold?: number;
101
- /**
102
- *
103
- * @type {Array<TableDto>}
104
- * @memberof UpdateProductVariantDto
105
- */
106
- tables?: Array<TableDto>;
107
- /**
108
- *
109
- * @type {Array<SingleProductMedia>}
110
- * @memberof UpdateProductVariantDto
111
- */
112
- productMedia?: Array<SingleProductMedia>;
113
106
  /**
114
107
  *
115
108
  * @type {number}
116
109
  * @memberof UpdateProductVariantDto
117
110
  */
118
- inventory?: number;
111
+ inventoryCount?: number;
119
112
  }
@@ -0,0 +1,51 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /**
4
+ * Hey Pharamcist API
5
+ * No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
6
+ *
7
+ * OpenAPI spec version: 1.0
8
+ *
9
+ *
10
+ * NOTE: This class is auto generated by the swagger code generator program.
11
+ * https://github.com/swagger-api/swagger-codegen.git
12
+ * Do not edit the class manually.
13
+ */
14
+ /**
15
+ *
16
+ * @export
17
+ * @interface Wishlist
18
+ */
19
+ export interface Wishlist {
20
+ _id?: string;
21
+ /**
22
+ *
23
+ * @type {Date}
24
+ * @memberof Wishlist
25
+ */
26
+ createdAt: Date;
27
+ /**
28
+ *
29
+ * @type {Date}
30
+ * @memberof Wishlist
31
+ */
32
+ updatedAt: Date;
33
+ /**
34
+ *
35
+ * @type {string}
36
+ * @memberof Wishlist
37
+ */
38
+ userId: string;
39
+ /**
40
+ *
41
+ * @type {Array<string>}
42
+ * @memberof Wishlist
43
+ */
44
+ products: Array<string>;
45
+ /**
46
+ *
47
+ * @type {number}
48
+ * @memberof Wishlist
49
+ */
50
+ itemCount: number;
51
+ }
@@ -1,6 +1,7 @@
1
1
  import globalAxios from "axios";
2
2
  import { Configuration } from "./configuration";
3
- import { getCookie } from 'cookies-next';
3
+ import { getCurrentConfig } from '../api-adapter/config';
4
+ import { getAuthToken } from '../api-adapter/config';
4
5
 
5
6
 
6
7
  // export const BaseUrl = "http://localhost:3333"; // local
@@ -15,12 +16,22 @@ globalAxios.interceptors.request.use(async (config) => {
15
16
  }
16
17
 
17
18
  if (typeof window !== 'undefined') {
18
- const token = getCookie('hey-pharmacist-token')
19
- const storeId = getCookie('x-store-key')
20
- if (token)
21
- config.headers.Authorization = `Bearer ${token}`
22
- if (storeId)
23
- config.headers["x-store-key"] = storeId;
19
+ try {
20
+ // Get storeId from configuration instead of cookies
21
+ const ecommerceConfig = getCurrentConfig();
22
+ const token = getAuthToken();
23
+
24
+ if (token) {
25
+ config.headers.Authorization = `Bearer ${token}`;
26
+ }
27
+
28
+ if (ecommerceConfig?.storeId) {
29
+ config.headers["X-Store-Key"] = ecommerceConfig.storeId;
30
+ }
31
+ } catch (error) {
32
+ // Configuration not initialized yet, skip adding headers
33
+ console.warn('API configuration not initialized yet:', error);
34
+ }
24
35
  }
25
36
 
26
37
  return config;
@@ -1,13 +1 @@
1
- /**
2
- * API Adapter - Main Export
3
- * Central export point for all adapters
4
- */
5
-
6
1
  export { initializeApiAdapter, getApiConfiguration, getCurrentConfig, setAuthToken, getAuthToken, clearAuthToken } from './config';
7
- export { authAdapter } from './auth-adapter';
8
- export { productsAdapter } from './products-adapter';
9
- export { cartAdapter } from './cart-adapter';
10
- export { ordersAdapter } from './orders-adapter';
11
- export type { CreateOrderData } from './orders-adapter';
12
- export * from './mappers';
13
-
@@ -8,47 +8,32 @@ export interface EcommerceConfig {
8
8
  secondary: string;
9
9
  accent: string;
10
10
  };
11
+ /** Optional hex colors to override header gradient */
12
+ headerGradient?: {
13
+ from: string; // hex color like #123456
14
+ via: string; // hex color
15
+ to: string; // hex color
16
+ };
11
17
  apiBaseUrl: string;
12
18
  stripePublicKey: string;
13
19
  }
14
20
 
15
- // Product Types
16
- export interface Product {
17
- id: string;
18
- name: string;
19
- description: string;
20
- price: number;
21
- compareAtPrice?: number;
22
- images: string[];
23
- category: string;
24
- inStock: boolean;
25
- stock?: number;
26
- sku?: string;
27
- tags?: string[];
28
- createdAt: string;
29
- updatedAt: string;
30
- }
21
+
22
+
23
+
24
+
25
+
31
26
 
32
27
  export interface ProductFilters {
33
28
  category?: string;
29
+ subCategory?: string;
34
30
  minPrice?: number;
35
31
  maxPrice?: number;
36
32
  search?: string;
37
33
  tags?: string[];
38
34
  inStock?: boolean;
39
- }
40
-
41
- // Cart Types
42
- export interface CartItem {
43
- productId: string;
44
- quantity: number;
45
- product: Product;
46
- }
47
-
48
- export interface Cart {
49
- items: CartItem[];
50
- total: number;
51
- itemCount: number;
35
+ ids?: string[];
36
+ newArrivals?: boolean;
52
37
  }
53
38
 
54
39
  // Order Types
@@ -60,39 +45,10 @@ export enum OrderStatus {
60
45
  CANCELLED = 'cancelled',
61
46
  }
62
47
 
63
- export interface Order {
64
- id: string;
65
- orderNumber: string;
66
- items: OrderItem[];
67
- total: number;
68
- status: OrderStatus;
69
- shippingAddress: Address;
70
- billingAddress: Address;
71
- paymentStatus: 'pending' | 'paid' | 'failed';
72
- stripeCheckoutUrl?: string;
73
- createdAt: string;
74
- updatedAt: string;
75
- }
76
48
 
77
- export interface OrderItem {
78
- id: string;
79
- productId: string;
80
- productName: string;
81
- productImage: string;
82
- quantity: number;
83
- price: number;
84
- }
49
+ export type AddressType = 'Billing' | 'Shipping' | 'Both';
50
+
85
51
 
86
- export interface Address {
87
- fullName: string;
88
- addressLine1: string;
89
- addressLine2?: string;
90
- city: string;
91
- state: string;
92
- zipCode: string;
93
- country: string;
94
- phone: string;
95
- }
96
52
 
97
53
  // Auth Types
98
54
  export interface User {
@@ -149,4 +105,3 @@ export interface Category {
149
105
  image?: string;
150
106
  productCount: number;
151
107
  }
152
-
@@ -24,7 +24,7 @@ export function generateColorShades(baseColor: string) {
24
24
  200: lighten(r, g, b, 0.75),
25
25
  300: lighten(r, g, b, 0.6),
26
26
  400: lighten(r, g, b, 0.3),
27
- 500: `${r}, ${g}, ${b}`,
27
+ 500: formatRgb(r, g, b),
28
28
  600: darken(r, g, b, 0.1),
29
29
  700: darken(r, g, b, 0.2),
30
30
  800: darken(r, g, b, 0.3),
@@ -35,17 +35,20 @@ export function generateColorShades(baseColor: string) {
35
35
  return shades;
36
36
  }
37
37
 
38
+ function formatRgb(r: number, g: number, b: number): string {
39
+ return `${r} ${g} ${b}`;
40
+ }
41
+
38
42
  function lighten(r: number, g: number, b: number, amount: number): string {
39
43
  const newR = Math.round(r + (255 - r) * amount);
40
44
  const newG = Math.round(g + (255 - g) * amount);
41
45
  const newB = Math.round(b + (255 - b) * amount);
42
- return `${newR}, ${newG}, ${newB}`;
46
+ return formatRgb(newR, newG, newB);
43
47
  }
44
48
 
45
49
  function darken(r: number, g: number, b: number, amount: number): string {
46
50
  const newR = Math.round(r * (1 - amount));
47
51
  const newG = Math.round(g * (1 - amount));
48
52
  const newB = Math.round(b * (1 - amount));
49
- return `${newR}, ${newG}, ${newB}`;
53
+ return formatRgb(newR, newG, newB);
50
54
  }
51
-
@@ -43,6 +43,6 @@ export function truncate(text: string, maxLength: number): string {
43
43
  * Generate initials from name
44
44
  */
45
45
  export function getInitials(firstName: string, lastName: string): string {
46
- return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
46
+ return `${firstName?.charAt(0)}${lastName?.charAt(0)}`.toUpperCase();
47
47
  }
48
48
 
@@ -0,0 +1,14 @@
1
+ import { z } from 'zod';
2
+
3
+ export const addressSchema = z.object({
4
+ name: z.string().min(2, 'Full name is required'),
5
+ street1: z.string().min(5, 'Address is required'),
6
+ street2: z.string().optional(),
7
+ city: z.string().min(2, 'City is required'),
8
+ state: z.string().min(2, 'State is required'),
9
+ zip: z.string().min(4, 'ZIP code is required'),
10
+ country: z.string().min(2, 'Country is required'),
11
+ phone: z.string().min(10, 'Phone number is required'),
12
+ });
13
+
14
+ export type AddressFormData = z.infer<typeof addressSchema>;
@@ -1,18 +1,19 @@
1
1
  'use client';
2
2
 
3
3
  import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
4
- import { User, LoginCredentials, RegisterData } from '@/lib/types';
5
- import { authApi } from '@/lib/api/auth';
6
- import { getAuthToken } from '@/lib/api/client';
4
+ import { getAuthToken, setAuthToken, clearAuthToken, getApiConfiguration } from '@/lib/api-adapter/config';
5
+ import { CreateUserDto, LoginDto, TUserSessionData, UpdateUserDto, UserEntity } from '@/lib/Apis/models';
6
+ import { UsersApi } from '@/lib/Apis/apis/users-api';
7
+ import { AuthApi } from '@/lib/Apis/apis/auth-api';
7
8
 
8
9
  interface AuthContextValue {
9
- user: User | null;
10
+ user: UserEntity | null;
10
11
  isAuthenticated: boolean;
11
12
  isLoading: boolean;
12
- login: (credentials: LoginCredentials) => Promise<void>;
13
- register: (data: RegisterData) => Promise<void>;
13
+ login: (credentials: LoginDto) => Promise<TUserSessionData>;
14
+ register: (data: CreateUserDto) => Promise<TUserSessionData>;
14
15
  logout: () => Promise<void>;
15
- updateUser: (data: Partial<User>) => Promise<void>;
16
+ updateUser: (data: UpdateUserDto) => Promise<UserEntity>;
16
17
  refreshUser: () => Promise<void>;
17
18
  }
18
19
 
@@ -31,17 +32,16 @@ interface AuthProviderProps {
31
32
  }
32
33
 
33
34
  export function AuthProvider({ children }: AuthProviderProps) {
34
- const [user, setUser] = useState<User | null>(null);
35
+ const [user, setUser] = useState<UserEntity | null>(null);
35
36
  const [isLoading, setIsLoading] = useState(true);
37
+ const USER_KEY = 'ecommerce_user';
36
38
 
37
39
  const refreshUser = useCallback(async () => {
38
40
  try {
39
41
  const token = getAuthToken();
40
42
  if (token) {
41
- const response = await authApi.getCurrentUser();
42
- if (response.success) {
43
- setUser(response.data);
44
- }
43
+ const response = await new UsersApi(getApiConfiguration()).getMyProfile();
44
+ setUser(response.data);
45
45
  }
46
46
  } catch (error) {
47
47
  console.error('Failed to refresh user:', error);
@@ -52,28 +52,53 @@ export function AuthProvider({ children }: AuthProviderProps) {
52
52
  }, []);
53
53
 
54
54
  useEffect(() => {
55
+ // Hydrate user instantly from localStorage for fast UI, then validate in background
56
+ if (typeof window !== 'undefined') {
57
+ try {
58
+ const cached = localStorage.getItem(USER_KEY);
59
+ if (cached) {
60
+ const parsed: UserEntity = JSON.parse(cached);
61
+ setUser(parsed);
62
+ setIsLoading(false);
63
+ }
64
+ } catch (_) {
65
+ // ignore cache parse errors
66
+ }
67
+ }
68
+ // Always attempt to refresh actual profile
55
69
  refreshUser();
56
70
  }, [refreshUser]);
57
71
 
58
- const login = async (credentials: LoginCredentials) => {
72
+ const login = async (credentials: LoginDto): Promise<TUserSessionData> => {
59
73
  setIsLoading(true);
60
74
  try {
61
- const response = await authApi.login(credentials);
62
- if (response.success) {
63
- setUser(response.data.user);
75
+ const response = await new AuthApi(getApiConfiguration()).signin(credentials);
76
+ // Persist access token and update user
77
+ if (response.data?.authToken) {
78
+ setAuthToken(response.data.authToken);
79
+ }
80
+ setUser(response.data.userData);
81
+ if (typeof window !== 'undefined') {
82
+ localStorage.setItem(USER_KEY, JSON.stringify(response.data.userData));
64
83
  }
84
+ return response.data;
65
85
  } finally {
66
86
  setIsLoading(false);
67
87
  }
68
88
  };
69
89
 
70
- const register = async (data: RegisterData) => {
90
+ const register = async (data: CreateUserDto): Promise<TUserSessionData> => {
71
91
  setIsLoading(true);
72
92
  try {
73
- const response = await authApi.register(data);
74
- if (response.success) {
75
- setUser(response.data.user);
93
+ const response = await new AuthApi(getApiConfiguration()).signup(data);
94
+ if (response.data?.authToken) {
95
+ setAuthToken(response.data.authToken);
96
+ }
97
+ setUser(response.data.userData);
98
+ if (typeof window !== 'undefined') {
99
+ localStorage.setItem(USER_KEY, JSON.stringify(response.data.userData));
76
100
  }
101
+ return response.data;
77
102
  } finally {
78
103
  setIsLoading(false);
79
104
  }
@@ -82,22 +107,27 @@ export function AuthProvider({ children }: AuthProviderProps) {
82
107
  const logout = async () => {
83
108
  setIsLoading(true);
84
109
  try {
85
- await authApi.logout();
110
+ clearAuthToken();
86
111
  setUser(null);
112
+ if (typeof window !== 'undefined') {
113
+ localStorage.removeItem(USER_KEY);
114
+ }
87
115
  } finally {
88
116
  setIsLoading(false);
89
117
  }
90
118
  };
91
119
 
92
- const updateUser = async (data: Partial<User>) => {
120
+ const updateUser = async (data: UpdateUserDto): Promise<UserEntity> => {
121
+ setIsLoading(true);
93
122
  try {
94
- const response = await authApi.updateProfile(data);
95
- if (response.success) {
96
- setUser(response.data);
97
- }
123
+ const response = await new UsersApi(getApiConfiguration()).updateMyProfile(data);
124
+ setUser(response.data);
125
+ return response.data;
98
126
  } catch (error) {
99
127
  console.error('Failed to update user:', error);
100
128
  throw error;
129
+ } finally {
130
+ setIsLoading(false);
101
131
  }
102
132
  };
103
133
 
@@ -105,11 +135,11 @@ export function AuthProvider({ children }: AuthProviderProps) {
105
135
  user,
106
136
  isAuthenticated: !!user,
107
137
  isLoading,
108
- login,
109
- register,
110
- logout,
111
- updateUser,
112
- refreshUser,
138
+ login: login as unknown as (credentials: LoginDto) => Promise<TUserSessionData>,
139
+ register: register as unknown as (data: CreateUserDto) => Promise<TUserSessionData>,
140
+ logout: logout as () => Promise<void>,
141
+ updateUser: updateUser as unknown as (data: UpdateUserDto) => Promise<UserEntity>,
142
+ refreshUser: refreshUser as () => Promise<void>,
113
143
  };
114
144
 
115
145
  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;