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.
- package/README.md +107 -1
- package/dist/index.d.mts +3636 -316
- package/dist/index.d.ts +3636 -316
- package/dist/index.js +6802 -3866
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6756 -3818
- package/dist/index.mjs.map +1 -1
- package/package.json +17 -14
- package/src/components/AddressFormModal.tsx +171 -0
- package/src/components/CartItem.tsx +17 -12
- package/src/components/FilterChips.tsx +195 -0
- package/src/components/Header.tsx +121 -71
- package/src/components/OrderCard.tsx +18 -25
- package/src/components/ProductCard.tsx +209 -72
- package/src/components/ui/Button.tsx +13 -5
- package/src/components/ui/Card.tsx +46 -0
- package/src/hooks/useAddresses.ts +83 -0
- package/src/hooks/useOrders.ts +37 -19
- package/src/hooks/useProducts.ts +55 -63
- package/src/hooks/useWishlistProducts.ts +75 -0
- package/src/index.ts +3 -19
- package/src/lib/Apis/api.ts +1 -0
- package/src/lib/Apis/apis/cart-api.ts +3 -3
- package/src/lib/Apis/apis/inventory-api.ts +0 -108
- package/src/lib/Apis/apis/stores-api.ts +70 -0
- package/src/lib/Apis/apis/wishlist-api.ts +447 -0
- package/src/lib/Apis/models/cart-item-populated.ts +0 -1
- package/src/lib/Apis/models/create-single-variant-product-dto.ts +3 -10
- package/src/lib/Apis/models/create-variant-dto.ts +26 -33
- package/src/lib/Apis/models/extended-product-dto.ts +20 -24
- package/src/lib/Apis/models/index.ts +2 -1
- package/src/lib/Apis/models/order-time-line-dto.ts +49 -0
- package/src/lib/Apis/models/order.ts +3 -8
- package/src/lib/Apis/models/populated-order.ts +3 -8
- package/src/lib/Apis/models/product-variant.ts +29 -0
- package/src/lib/Apis/models/update-product-variant-dto.ts +16 -23
- package/src/lib/Apis/models/wishlist.ts +51 -0
- package/src/lib/Apis/wrapper.ts +18 -7
- package/src/lib/api-adapter/index.ts +0 -12
- package/src/lib/types/index.ts +16 -61
- package/src/lib/utils/colors.ts +7 -4
- package/src/lib/utils/format.ts +1 -1
- package/src/lib/validations/address.ts +14 -0
- package/src/providers/AuthProvider.tsx +61 -31
- package/src/providers/CartProvider.tsx +18 -28
- package/src/providers/EcommerceProvider.tsx +7 -0
- package/src/providers/FavoritesProvider.tsx +86 -0
- package/src/providers/ThemeProvider.tsx +16 -1
- package/src/providers/WishlistProvider.tsx +174 -0
- package/src/screens/AddressesScreen.tsx +484 -0
- package/src/screens/CartScreen.tsx +120 -84
- package/src/screens/CategoriesScreen.tsx +120 -0
- package/src/screens/CheckoutScreen.tsx +919 -241
- package/src/screens/CurrentOrdersScreen.tsx +125 -61
- package/src/screens/HomeScreen.tsx +209 -0
- package/src/screens/LoginScreen.tsx +133 -88
- package/src/screens/NewAddressScreen.tsx +187 -0
- package/src/screens/OrdersScreen.tsx +162 -50
- package/src/screens/ProductDetailScreen.tsx +641 -190
- package/src/screens/ProfileScreen.tsx +192 -116
- package/src/screens/RegisterScreen.tsx +193 -144
- package/src/screens/SearchResultsScreen.tsx +165 -0
- package/src/screens/ShopScreen.tsx +1110 -146
- package/src/screens/WishlistScreen.tsx +428 -0
- package/src/lib/Apis/models/inventory-paginated-response.ts +0 -75
- package/src/lib/api/auth.ts +0 -81
- package/src/lib/api/cart.ts +0 -42
- package/src/lib/api/orders.ts +0 -53
- package/src/lib/api/products.ts +0 -51
- package/src/lib/api-adapter/auth-adapter.ts +0 -196
- package/src/lib/api-adapter/cart-adapter.ts +0 -193
- package/src/lib/api-adapter/mappers.ts +0 -152
- package/src/lib/api-adapter/orders-adapter.ts +0 -195
- 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<
|
|
145
|
+
* @type {Array<OrderTimeLineDTO>}
|
|
145
146
|
* @memberof Order
|
|
146
147
|
*/
|
|
147
|
-
orderTimeLine: Array<
|
|
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<
|
|
134
|
+
* @type {Array<OrderTimeLineDTO>}
|
|
134
135
|
* @memberof PopulatedOrder
|
|
135
136
|
*/
|
|
136
|
-
orderTimeLine?: Array<
|
|
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
|
-
|
|
27
|
+
name?: string;
|
|
29
28
|
/**
|
|
30
29
|
*
|
|
31
|
-
* @type {
|
|
30
|
+
* @type {Array<SingleProductMedia>}
|
|
32
31
|
* @memberof UpdateProductVariantDto
|
|
33
32
|
*/
|
|
34
|
-
|
|
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
|
-
|
|
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
|
+
}
|
package/src/lib/Apis/wrapper.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import globalAxios from "axios";
|
|
2
2
|
import { Configuration } from "./configuration";
|
|
3
|
-
import {
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
package/src/lib/types/index.ts
CHANGED
|
@@ -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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
78
|
-
|
|
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
|
-
|
package/src/lib/utils/colors.ts
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
|
53
|
+
return formatRgb(newR, newG, newB);
|
|
50
54
|
}
|
|
51
|
-
|
package/src/lib/utils/format.ts
CHANGED
|
@@ -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
|
|
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 {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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:
|
|
10
|
+
user: UserEntity | null;
|
|
10
11
|
isAuthenticated: boolean;
|
|
11
12
|
isLoading: boolean;
|
|
12
|
-
login: (credentials:
|
|
13
|
-
register: (data:
|
|
13
|
+
login: (credentials: LoginDto) => Promise<TUserSessionData>;
|
|
14
|
+
register: (data: CreateUserDto) => Promise<TUserSessionData>;
|
|
14
15
|
logout: () => Promise<void>;
|
|
15
|
-
updateUser: (data:
|
|
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<
|
|
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
|
|
42
|
-
|
|
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:
|
|
72
|
+
const login = async (credentials: LoginDto): Promise<TUserSessionData> => {
|
|
59
73
|
setIsLoading(true);
|
|
60
74
|
try {
|
|
61
|
-
const response = await
|
|
62
|
-
|
|
63
|
-
|
|
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:
|
|
90
|
+
const register = async (data: CreateUserDto): Promise<TUserSessionData> => {
|
|
71
91
|
setIsLoading(true);
|
|
72
92
|
try {
|
|
73
|
-
const response = await
|
|
74
|
-
if (response.
|
|
75
|
-
|
|
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
|
-
|
|
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:
|
|
120
|
+
const updateUser = async (data: UpdateUserDto): Promise<UserEntity> => {
|
|
121
|
+
setIsLoading(true);
|
|
93
122
|
try {
|
|
94
|
-
const response = await
|
|
95
|
-
|
|
96
|
-
|
|
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>;
|