1
+ import { config } from '@/config' ;
2
+
3
+ // Types
4
+ export interface User {
5
+ id : string ;
6
+ email : string ;
7
+ name : string ;
8
+ token : string ;
9
+ roles : string [ ] ;
10
+ }
11
+
12
+ export interface UserResponse {
13
+ user : {
14
+ id : string ;
15
+ email : string ;
16
+ first_name : string ;
17
+ last_name : string ;
18
+ roles : string [ ] ;
19
+ } ;
20
+ token : string ;
21
+ }
22
+
23
+ export interface Profile {
24
+ first_name : string ;
25
+ last_name : string ;
26
+ phone_number : string ;
27
+ street_1 : string ;
28
+ street_2 : string ;
29
+ city : string ;
30
+ state : string ;
31
+ zip : string ;
32
+ }
33
+
34
+ export interface Order {
35
+ id : string ;
36
+ created : string ;
37
+ status : string ;
38
+ payment_status : string ;
39
+ delivery_fee : number ;
40
+ total_amount : number ;
41
+ tax_amount : number ;
42
+ delivery_address ?: {
43
+ street_address : string [ ] ;
44
+ city : string ;
45
+ state : string ;
46
+ zip_code : string ;
47
+ } ;
48
+ customer_phone ?: string ;
49
+ stores : {
50
+ store : {
51
+ id : string ;
52
+ name : string ;
53
+ } ;
54
+ items : {
55
+ id : string ;
56
+ name : string ;
57
+ quantity : number ;
58
+ price : number ;
59
+ } [ ] ;
60
+ } [ ] ;
61
+ }
62
+
63
+ export interface Store {
64
+ id : string ;
65
+ name : string ;
66
+ street_1 : string ;
67
+ street_2 ?: string ;
68
+ city : string ;
69
+ state : string ;
70
+ zip_code : string ;
71
+ instagram ?: string ;
72
+ facebook ?: string ;
73
+ twitter ?: string ;
74
+ items ?: StoreItem [ ] ;
75
+ }
76
+
77
+ export interface StoreItem {
78
+ id : string ;
79
+ name : string ;
80
+ description : string ;
81
+ price : number ;
82
+ quantity : number ;
83
+ imageUrl ?: string ;
84
+ }
85
+
86
+ export interface SavedCard {
87
+ id : string ;
88
+ last4 : string ;
89
+ brand : string ;
90
+ exp_month : number ;
91
+ exp_year : number ;
92
+ isDefault : boolean ;
93
+ }
94
+
95
+ export interface OrderCreateData {
96
+ token : string ;
97
+ user_id : string ;
98
+ store_id : string ;
99
+ payment_method_id : string ;
100
+ items : {
101
+ store_item_id : string ;
102
+ quantity : number ;
103
+ price : number ;
104
+ } [ ] ;
105
+ subtotal_amount : number ;
106
+ tax_amount : number ;
107
+ delivery_fee : number ;
108
+ total_amount : number ;
109
+ delivery_address : {
110
+ street_address : string [ ] ;
111
+ city : string ;
112
+ state : string ;
113
+ zip_code : string ;
114
+ country : string ;
115
+ } ;
116
+ }
117
+
118
+ // Helper function to handle API responses
119
+ async function handleResponse < T > ( response : Response ) : Promise < T > {
120
+ if ( ! response . ok ) {
121
+ const errorData = await response . json ( ) . catch ( ( ) => ( { } ) ) ;
122
+ throw new Error ( errorData . detail || `API Error: ${ response . status } ` ) ;
123
+ }
124
+ return response . json ( ) ;
125
+ }
126
+
127
+ // Auth API
128
+ export const authApi = {
129
+ login : async ( email : string , password : string ) : Promise < UserResponse > => {
130
+ const response = await fetch ( `${ config . apiUrl } /api/v0/auth/login` , {
131
+ method : 'POST' ,
132
+ headers : { 'Content-Type' : 'application/json' } ,
133
+ body : JSON . stringify ( { email, password } ) ,
134
+ } ) ;
135
+ return handleResponse ( response ) ;
136
+ } ,
137
+
138
+ signup : async ( email : string , password : string , first_name : string , last_name : string ) : Promise < UserResponse > => {
139
+ const response = await fetch ( `${ config . apiUrl } /api/v0/auth/signup` , {
140
+ method : 'POST' ,
141
+ headers : { 'Content-Type' : 'application/json' } ,
142
+ body : JSON . stringify ( {
143
+ email,
144
+ password,
145
+ passwordConfirm : password ,
146
+ first_name,
147
+ last_name
148
+ } ) ,
149
+ } ) ;
150
+ return handleResponse ( response ) ;
151
+ } ,
152
+
153
+ getProfile : async ( token : string ) : Promise < Profile > => {
154
+ const response = await fetch ( `${ config . apiUrl } /api/v0/auth/profile` , {
155
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
156
+ } ) ;
157
+ return handleResponse ( response ) ;
158
+ } ,
159
+
160
+ updateProfile : async ( token : string , profile : Partial < Profile > ) : Promise < Profile > => {
161
+ const response = await fetch ( `${ config . apiUrl } /api/v0/auth/profile` , {
162
+ method : 'PATCH' ,
163
+ headers : {
164
+ 'Authorization' : `Bearer ${ token } ` ,
165
+ 'Content-Type' : 'application/json' ,
166
+ } ,
167
+ body : JSON . stringify ( profile ) ,
168
+ } ) ;
169
+ return handleResponse ( response ) ;
170
+ } ,
171
+ } ;
172
+
173
+ // Orders API
174
+ export const ordersApi = {
175
+ getUserOrders : async ( token : string ) : Promise < Order [ ] > => {
176
+ const response = await fetch ( `${ config . apiUrl } /api/v0/user/orders` , {
177
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
178
+ } ) ;
179
+ return handleResponse ( response ) ;
180
+ } ,
181
+
182
+ getAdminOrders : async ( token : string ) : Promise < Order [ ] > => {
183
+ const response = await fetch ( `${ config . apiUrl } /api/v0/orders` , {
184
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
185
+ } ) ;
186
+ return handleResponse ( response ) ;
187
+ } ,
188
+
189
+ getOrder : async ( token : string , orderId : string ) : Promise < Order > => {
190
+ const response = await fetch ( `${ config . apiUrl } /api/v0/orders/${ orderId } ` , {
191
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
192
+ } ) ;
193
+ return handleResponse ( response ) ;
194
+ } ,
195
+
196
+ createOrder : async ( token : string , orderData : OrderCreateData ) : Promise < Order > => {
197
+ const response = await fetch ( `${ config . apiUrl } /api/v0/orders` , {
198
+ method : 'POST' ,
199
+ headers : {
200
+ 'Authorization' : `Bearer ${ token } ` ,
201
+ 'Content-Type' : 'application/json' ,
202
+ } ,
203
+ body : JSON . stringify ( orderData ) ,
204
+ } ) ;
205
+ return handleResponse ( response ) ;
206
+ } ,
207
+
208
+ getOrderById : async ( token : string , orderId : string ) : Promise < Order > => {
209
+ const response = await fetch ( `${ config . apiUrl } /api/v0/orders/${ orderId } ` , {
210
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
211
+ } ) ;
212
+ return handleResponse ( response ) ;
213
+ } ,
214
+
215
+ updateOrderStatus : async ( token : string , orderId : string , status : string ) : Promise < Order > => {
216
+ const response = await fetch ( `${ config . apiUrl } /api/v0/orders/${ orderId } /status` , {
217
+ method : 'PATCH' ,
218
+ headers : {
219
+ 'Authorization' : `Bearer ${ token } ` ,
220
+ 'Content-Type' : 'application/json' ,
221
+ } ,
222
+ body : JSON . stringify ( { status } ) ,
223
+ } ) ;
224
+ return handleResponse ( response ) ;
225
+ } ,
226
+ } ;
227
+
228
+ // Stores API
229
+ export const storesApi = {
230
+ getAllStores : async ( ) : Promise < Store [ ] > => {
231
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores` ) ;
232
+ return handleResponse ( response ) ;
233
+ } ,
234
+
235
+ getStore : async ( storeId : string ) : Promise < Store > => {
236
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores/${ storeId } ` ) ;
237
+ return handleResponse ( response ) ;
238
+ } ,
239
+
240
+ getStoreItems : async ( storeId : string ) : Promise < StoreItem [ ] > => {
241
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores/${ storeId } /items` ) ;
242
+ return handleResponse ( response ) ;
243
+ } ,
244
+
245
+ getStoreOrders : async ( token : string , storeId : string ) : Promise < Order [ ] > => {
246
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores/${ storeId } /orders` , {
247
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
248
+ } ) ;
249
+ return handleResponse ( response ) ;
250
+ } ,
251
+
252
+ getStoreRoles : async ( token : string , storeId : string ) : Promise < { roles : string [ ] } > => {
253
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores/${ storeId } /roles` , {
254
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
255
+ } ) ;
256
+ return handleResponse ( response ) ;
257
+ } ,
258
+
259
+ createStoreItem : async ( token : string , storeId : string , itemData : Partial < StoreItem > ) : Promise < StoreItem > => {
260
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores/${ storeId } /items` , {
261
+ method : 'POST' ,
262
+ headers : {
263
+ 'Authorization' : `Bearer ${ token } ` ,
264
+ 'Content-Type' : 'application/json' ,
265
+ } ,
266
+ body : JSON . stringify ( itemData ) ,
267
+ } ) ;
268
+ return handleResponse ( response ) ;
269
+ } ,
270
+
271
+ updateStoreItem : async ( token : string , storeId : string , itemId : string , itemData : Partial < StoreItem > ) : Promise < StoreItem > => {
272
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores/${ storeId } /items/${ itemId } ` , {
273
+ method : 'PATCH' ,
274
+ headers : {
275
+ 'Authorization' : `Bearer ${ token } ` ,
276
+ 'Content-Type' : 'application/json' ,
277
+ } ,
278
+ body : JSON . stringify ( itemData ) ,
279
+ } ) ;
280
+ return handleResponse ( response ) ;
281
+ } ,
282
+
283
+ deleteStoreItem : async ( token : string , storeId : string , itemId : string ) : Promise < void > => {
284
+ const response = await fetch ( `${ config . apiUrl } /api/v0/stores/${ storeId } /items/${ itemId } ` , {
285
+ method : 'DELETE' ,
286
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
287
+ } ) ;
288
+ return handleResponse ( response ) ;
289
+ } ,
290
+
291
+ getStoreWithItems : async ( storeId : string ) : Promise < Store & { items : StoreItem [ ] } > => {
292
+ const [ store , items ] = await Promise . all ( [
293
+ storesApi . getStore ( storeId ) ,
294
+ storesApi . getStoreItems ( storeId )
295
+ ] ) ;
296
+ return {
297
+ ...store ,
298
+ items : items . map ( item => ( {
299
+ ...item ,
300
+ imageUrl : `https://picsum.photos/seed/${ item . id } /400/300`
301
+ } ) )
302
+ } ;
303
+ } ,
304
+
305
+ getAllStoresWithItems : async ( ) : Promise < ( Store & { items : StoreItem [ ] } ) [ ] > => {
306
+ const stores = await storesApi . getAllStores ( ) ;
307
+ const storesWithItems = await Promise . all (
308
+ stores . map ( async ( store ) => {
309
+ const items = await storesApi . getStoreItems ( store . id ) ;
310
+ return {
311
+ ...store ,
312
+ items : items . map ( item => ( {
313
+ ...item ,
314
+ imageUrl : `https://picsum.photos/seed/${ item . id } /400/300`
315
+ } ) )
316
+ } ;
317
+ } )
318
+ ) ;
319
+ return storesWithItems ;
320
+ } ,
321
+ } ;
322
+
323
+ // Payment API
324
+ export const paymentApi = {
325
+ getCards : async ( token : string ) : Promise < SavedCard [ ] > => {
326
+ const response = await fetch ( `${ config . apiUrl } /api/v0/payment/cards` , {
327
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
328
+ } ) ;
329
+ if ( response . status === 404 ) return [ ] ;
330
+ return handleResponse ( response ) ;
331
+ } ,
332
+
333
+ createSetupIntent : async ( token : string ) : Promise < { clientSecret : string } > => {
334
+ const response = await fetch ( `${ config . apiUrl } /api/v0/payment/setup-intent` , {
335
+ method : 'POST' ,
336
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
337
+ } ) ;
338
+ return handleResponse ( response ) ;
339
+ } ,
340
+
341
+ attachCard : async ( token : string , paymentMethodId : string ) : Promise < SavedCard > => {
342
+ const response = await fetch ( `${ config . apiUrl } /api/v0/payment/cards` , {
343
+ method : 'POST' ,
344
+ headers : {
345
+ 'Authorization' : `Bearer ${ token } ` ,
346
+ 'Content-Type' : 'application/json' ,
347
+ } ,
348
+ body : JSON . stringify ( { payment_method_id : paymentMethodId } ) ,
349
+ } ) ;
350
+ return handleResponse ( response ) ;
351
+ } ,
352
+
353
+ deleteCard : async ( token : string , cardId : string ) : Promise < void > => {
354
+ const response = await fetch ( `${ config . apiUrl } /api/v0/payment/cards/${ cardId } ` , {
355
+ method : 'DELETE' ,
356
+ headers : { 'Authorization' : `Bearer ${ token } ` } ,
357
+ } ) ;
358
+ return handleResponse ( response ) ;
359
+ } ,
360
+ } ;
361
+
362
+ // Search API
363
+ export const searchApi = {
364
+ searchProducts : async ( query : string ) : Promise < any [ ] > => {
365
+ const response = await fetch (
366
+ `${ config . searchUrl } /api/search?query=${ encodeURIComponent ( query ) } &index=products`
367
+ ) ;
368
+ const { hits } = await handleResponse < { hits : any [ ] } > ( response ) ;
369
+ return hits ;
370
+ } ,
371
+ } ;
0 commit comments