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
@@ -0,0 +1,428 @@
1
+ 'use client';
2
+
3
+ import React, { useEffect, useMemo, useState } from 'react';
4
+ import { motion, AnimatePresence } from 'framer-motion';
5
+ import {
6
+ Grid,
7
+ Heart,
8
+ List,
9
+ LucideIcon,
10
+ Package,
11
+ ShieldCheck,
12
+ ShoppingBag,
13
+ Sparkles,
14
+ Trash2,
15
+ } from 'lucide-react';
16
+ import { useRouter } from 'next/navigation';
17
+ import { toast } from 'sonner';
18
+ import { ProductCard } from '@/components/ProductCard';
19
+ import { Button } from '@/components/ui/Button';
20
+ import { useWishlist } from '@/providers/WishlistProvider';
21
+ import { useAuth } from '@/providers/AuthProvider';
22
+ import { useWishlistProducts } from '@/hooks/useWishlistProducts';
23
+ import Image from 'next/image';
24
+ import { formatPrice } from '@/lib/utils/format';
25
+ import { ExtendedProductDTO } from '@/lib/Apis';
26
+
27
+ type SortOption = 'featured' | 'price-low' | 'price-high' | 'name' | 'availability';
28
+
29
+ const SORT_OPTIONS: { value: SortOption; label: string }[] = [
30
+ { value: 'featured', label: 'Most loved' },
31
+ { value: 'price-low', label: 'Price: Low to High' },
32
+ { value: 'price-high', label: 'Price: High to Low' },
33
+ { value: 'name', label: 'Name A-Z' },
34
+ { value: 'availability', label: 'Availability' },
35
+ ];
36
+
37
+ interface InsightCardProps {
38
+ icon: LucideIcon;
39
+ title: string;
40
+ value: string;
41
+ helper?: string;
42
+ accentClassName: string;
43
+ }
44
+
45
+
46
+ export default function WishlistScreen() {
47
+ const router = useRouter();
48
+ const { isAuthenticated } = useAuth() || {};
49
+ const {
50
+ products: wishlistItems,
51
+ removeFromWishlist,
52
+ getWishlistCount,
53
+ clearWishlist,
54
+ refreshWishlist,
55
+ } = useWishlist();
56
+
57
+ const wishlistCount = getWishlistCount?.() ?? 0;
58
+ const { products: wishlistProducts, isLoading, error } = useWishlistProducts(
59
+ wishlistItems as string[]
60
+ );
61
+
62
+ const [onlyInStock, setOnlyInStock] = useState(false);
63
+ const [viewMode, setViewMode] = useState<'grid' | 'list'>('list');
64
+ const [sortOption, setSortOption] = useState<SortOption>('featured');
65
+
66
+ useEffect(() => {
67
+ if (error) {
68
+ toast.error('We had trouble loading your saved products. Please try again.');
69
+ }
70
+ }, [error]);
71
+
72
+ const handleRemoveFromWishlist = async (productId: string) => {
73
+ try {
74
+ await removeFromWishlist(productId);
75
+ } catch (err) {
76
+ console.error('Error removing from wishlist:', err);
77
+ }
78
+ };
79
+
80
+ const handleClearWishlist = async () => {
81
+ const confirmed = window.confirm('Clear all items from your wishlist?');
82
+ if (!confirmed) return;
83
+ try {
84
+ await clearWishlist();
85
+ await refreshWishlist();
86
+ } catch (err) {
87
+ console.error('Error clearing wishlist:', err);
88
+ }
89
+ };
90
+
91
+ const totalValue = useMemo(
92
+ () => wishlistProducts.reduce((sum, product) => sum + (product.finalPrice ?? 0), 0),
93
+ [wishlistProducts]
94
+ );
95
+
96
+ const totalSavings = useMemo(
97
+ () =>
98
+ wishlistProducts.reduce((sum, product) => {
99
+ const before = product.priceBeforeDiscount ?? product.finalPrice ?? 0;
100
+ const after = product.finalPrice ?? 0;
101
+ const savings = Math.max(before - after, 0);
102
+ return sum + savings;
103
+ }, 0),
104
+ [wishlistProducts]
105
+ );
106
+
107
+ const inStockCount = useMemo(
108
+ () => wishlistProducts.filter((product) => (product.inventoryCount ?? 0) > 0).length,
109
+ [wishlistProducts]
110
+ );
111
+
112
+ const processedProducts = useMemo(() => {
113
+ let list = [...wishlistProducts];
114
+
115
+ if (onlyInStock) {
116
+ list = list.filter((product) => (product.inventoryCount ?? 0) > 0);
117
+ }
118
+
119
+ switch (sortOption) {
120
+ case 'price-low':
121
+ list.sort((a, b) => (a.finalPrice ?? 0) - (b.finalPrice ?? 0));
122
+ break;
123
+ case 'price-high':
124
+ list.sort((a, b) => (b.finalPrice ?? 0) - (a.finalPrice ?? 0));
125
+ break;
126
+ case 'name':
127
+ list.sort((a, b) => (a.name || '').localeCompare(b.name || ''));
128
+ break;
129
+ case 'availability':
130
+ list.sort((a, b) => (b.inventoryCount ?? 0) - (a.inventoryCount ?? 0));
131
+ break;
132
+ case 'featured':
133
+ default:
134
+ list.sort((a, b) => (b.totalSold ?? 0) - (a.totalSold ?? 0));
135
+ break;
136
+ }
137
+
138
+ return list;
139
+ }, [wishlistProducts, onlyInStock, sortOption]);
140
+
141
+ const emptyAfterFiltering = !isLoading && wishlistProducts.length > 0 && processedProducts.length === 0;
142
+
143
+ return (
144
+ <div className="min-h-screen bg-slate-50 pb-16">
145
+ <section className="relative overflow-hidden bg-gradient-to-br from-[rgb(var(--header-from))] via-[rgb(var(--header-via))] to-[rgb(var(--header-to))] pb-32 pt-16 text-white">
146
+ <div className="absolute inset-0 opacity-40 mix-blend-soft-light" aria-hidden="true">
147
+ <div className="absolute -top-1/2 right-1/2 h-[40rem] w-[40rem] rounded-full bg-white/10 blur-3xl" />
148
+ <div className="absolute left-1/4 top-1/4 h-48 w-48 rounded-full bg-white/20 blur-2xl" />
149
+ </div>
150
+ <div className="relative container mx-auto px-4">
151
+ <div className="max-w-3xl space-y-6">
152
+ <span className="inline-flex items-center gap-2 rounded-full bg-white/15 px-4 py-1 text-sm font-semibold uppercase tracking-[0.35em] text-white/70 backdrop-blur">
153
+ <Heart className="h-4 w-4" />
154
+ Wishlist
155
+ </span>
156
+ <h1 className="text-4xl font-bold leading-tight md:text-5xl">
157
+ Curate your pharmacy must-haves in one calming space
158
+ </h1>
159
+ <p className="max-w-2xl text-white/80 md:text-lg">
160
+ We keep your favourite products ready for reorder, refill reminders, and quick checkout—exactly when you need them.
161
+ </p>
162
+ </div>
163
+ </div>
164
+ </section>
165
+
166
+ <div className="relative -mt-20">
167
+ <div className="container mx-auto px-4">
168
+ <motion.div
169
+ initial={{ opacity: 0, y: 24 }}
170
+ animate={{ opacity: 1, y: 0 }}
171
+ className="rounded-3xl border border-slate-100 bg-white p-6 shadow-xl shadow-primary-50"
172
+ >
173
+ <div className="flex flex-col gap-6">
174
+ {!isAuthenticated && (
175
+ <div className="flex min-h-[40vh] items-center justify-center">
176
+ <div className="max-w-lg rounded-3xl border border-slate-100 bg-white p-10 text-center shadow-lg shadow-primary-50">
177
+ <div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-primary-50 text-primary-600">
178
+ <Heart className="h-8 w-8" />
179
+ </div>
180
+ <h2 className="mt-6 text-3xl font-bold text-slate-900">Sign in to see your favourites</h2>
181
+ <p className="mt-3 text-slate-500">
182
+ Create your curated shelf of products and we&apos;ll keep them ready whenever you return.
183
+ </p>
184
+ <Button className="mt-6" onClick={() => router.push('/login')}>
185
+ Sign In
186
+ </Button>
187
+ </div>
188
+ </div>
189
+ )}
190
+
191
+ {isAuthenticated && (
192
+ <>
193
+ <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
194
+ <div className="space-y-1">
195
+ <h2 className="text-2xl font-semibold text-slate-900">Your saved collection</h2>
196
+ <p className="text-sm text-slate-500">
197
+ Total value: <span className="font-semibold text-primary-600">{formatPrice(totalValue)}</span>
198
+ {onlyInStock && ' • Showing items ready to ship'}
199
+ </p>
200
+ </div>
201
+
202
+ <div className="flex flex-wrap items-center gap-3">
203
+ <label className="inline-flex cursor-pointer items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1.5 text-sm font-medium text-slate-600 transition hover:border-primary-200 hover:text-primary-600">
204
+ <input
205
+ type="checkbox"
206
+ checked={onlyInStock}
207
+ onChange={(event) => setOnlyInStock(event.target.checked)}
208
+ className="h-4 w-4 rounded border-slate-300 text-primary-600 focus:ring-primary-500"
209
+ />
210
+ Only show in-stock
211
+ </label>
212
+
213
+ <div className="flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1.5 text-sm text-slate-600">
214
+ <span>Sort</span>
215
+ <select
216
+ value={sortOption}
217
+ onChange={(event) => setSortOption(event.target.value as SortOption)}
218
+ className="bg-transparent text-sm font-medium text-slate-700 outline-none"
219
+ >
220
+ {SORT_OPTIONS.map((option) => (
221
+ <option key={option.value} value={option.value}>
222
+ {option.label}
223
+ </option>
224
+ ))}
225
+ </select>
226
+ </div>
227
+
228
+ <div className="flex overflow-hidden rounded-full border border-slate-200 bg-slate-50">
229
+ <button
230
+ type="button"
231
+ onClick={() => setViewMode('grid')}
232
+ className={`flex items-center gap-1 px-3 py-1.5 text-sm font-medium transition ${viewMode === 'grid'
233
+ ? 'bg-primary-600 text-white shadow-lg shadow-primary-500/30'
234
+ : 'text-slate-600 hover:bg-white'
235
+ }`}
236
+ >
237
+ <Grid className="h-4 w-4" />
238
+ Grid
239
+ </button>
240
+ <button
241
+ type="button"
242
+ onClick={() => setViewMode('list')}
243
+ className={`flex items-center gap-1 px-3 py-1.5 text-sm font-medium transition ${viewMode === 'list'
244
+ ? 'bg-primary-600 text-white shadow-lg shadow-primary-500/30'
245
+ : 'text-slate-600 hover:bg-white'
246
+ }`}
247
+ >
248
+ <List className="h-4 w-4" />
249
+ List
250
+ </button>
251
+ </div>
252
+
253
+ {wishlistCount > 0 && (
254
+ <Button
255
+ variant="ghost"
256
+ className="text-sm font-semibold text-slate-500 hover:text-red-500"
257
+ onClick={handleClearWishlist}
258
+ >
259
+ <Trash2 className="h-4 w-4" />
260
+ Clear all
261
+ </Button>
262
+ )}
263
+ </div>
264
+ </div>
265
+
266
+ {isLoading && (
267
+ <div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3">
268
+ {Array.from({ length: Math.min(wishlistCount || 3, 6) }).map((_, index) => (
269
+ <div
270
+ key={index}
271
+ className="h-72 animate-pulse rounded-2xl border border-slate-200 bg-slate-100"
272
+ />
273
+ ))}
274
+ </div>
275
+ )}
276
+
277
+ {!isLoading && wishlistCount === 0 && (
278
+ <div className="flex min-h-[30vh] items-center justify-center">
279
+ <div className="max-w-2xl rounded-3xl border border-slate-100 bg-white p-12 text-center shadow-xl shadow-primary-50">
280
+ <div className="mx-auto flex h-20 w-20 items-center justify-center rounded-full bg-primary-100 text-primary-600">
281
+ <Sparkles className="h-10 w-10" />
282
+ </div>
283
+ <h2 className="mt-6 text-4xl font-bold text-slate-900">Start your wellness wishlist</h2>
284
+ <p className="mt-4 text-lg text-slate-500">
285
+ Bookmark pharmacy essentials, supplements, or skincare picks and we&apos;ll keep them safe until you&apos;re ready to checkout.
286
+ </p>
287
+ <div className="mt-8 flex flex-wrap justify-center gap-3">
288
+ <Button onClick={() => router.push('/shop')}>Discover products</Button>
289
+ <Button variant="outline" onClick={() => router.push('/categories')}>
290
+ Browse categories
291
+ </Button>
292
+ </div>
293
+ </div>
294
+ </div>
295
+ )}
296
+
297
+
298
+ {!isLoading && processedProducts.length > 0 && (
299
+ <>
300
+ {viewMode === 'grid' ? (
301
+ <motion.div
302
+ layout
303
+ className="grid grid-cols-1 gap-5 sm:grid-cols-2 xl:grid-cols-3"
304
+ >
305
+ <AnimatePresence>
306
+ {processedProducts.map((product) => (
307
+ <motion.div
308
+ key={product.id}
309
+ layout
310
+ initial={{ opacity: 0, y: 20 }}
311
+ animate={{ opacity: 1, y: 0 }}
312
+ exit={{ opacity: 0, y: -20 }}
313
+ transition={{ duration: 0.2 }}
314
+ >
315
+ <ProductCard
316
+ product={product as ExtendedProductDTO}
317
+ onClickProduct={(p) => router.push(`/products/${p.id}`)}
318
+ onFavorite={() => handleRemoveFromWishlist(product.id)}
319
+ isFavorited
320
+ />
321
+ </motion.div>
322
+ ))}
323
+ </AnimatePresence>
324
+ </motion.div>
325
+ ) : (
326
+ <motion.div layout className="space-y-4">
327
+ <AnimatePresence>
328
+ {processedProducts.map((product) => (
329
+ <motion.div
330
+ key={product.id}
331
+ layout
332
+ initial={{ opacity: 0, y: 20 }}
333
+ animate={{ opacity: 1, y: 0 }}
334
+ exit={{ opacity: 0, y: -20 }}
335
+ transition={{ duration: 0.2 }}
336
+ className="flex flex-col gap-4 rounded-2xl border border-slate-100 bg-slate-50 p-4 shadow-sm shadow-primary-50 sm:flex-row sm:items-center"
337
+ >
338
+ <div className="relative h-28 w-full overflow-hidden rounded-2xl bg-white sm:w-40">
339
+ <Image
340
+ fill
341
+ src={product.productMedia?.[0]?.file || '/placeholder-product.jpg'}
342
+ alt={product.name || 'Wishlist item'}
343
+ className="h-full w-full object-cover"
344
+ />
345
+ </div>
346
+ <div className="flex flex-1 flex-col gap-2">
347
+ <div className="flex flex-wrap items-center justify-between gap-3">
348
+ <div>
349
+ <h3 className="text-lg font-semibold text-slate-900">
350
+ {product.name}
351
+ </h3>
352
+ <p className="text-sm text-slate-500">
353
+ {product.parentCategories?.map((category) => category?.name).join(', ') || 'General wellness'}
354
+ </p>
355
+ </div>
356
+ <div className="text-right">
357
+ <p className="text-lg font-bold text-primary-600">
358
+ {formatPrice(product.finalPrice ?? 0)}
359
+ </p>
360
+ {product.isDiscounted && (
361
+ <p className="text-xs text-emerald-500">
362
+ You save {formatPrice(Math.max((product.priceBeforeDiscount ?? 0) - (product.finalPrice ?? 0), 0))}
363
+ </p>
364
+ )}
365
+ </div>
366
+ </div>
367
+ <div className="flex flex-wrap items-center gap-3 text-xs text-slate-500">
368
+ <span className={`inline-flex items-center gap-1 rounded-full px-2.5 py-1 font-medium ${product.inventoryCount > 0 ? 'bg-emerald-100 text-emerald-700' : 'bg-rose-100 text-rose-700'}`}>
369
+ <Package className="h-3.5 w-3.5" />
370
+ {product.inventoryCount > 0 ? 'In stock' : 'Backordered'}
371
+ </span>
372
+ {product.totalSold > 0 && (
373
+ <span className="inline-flex items-center gap-1 rounded-full bg-slate-200 px-2.5 py-1 font-medium text-slate-700">
374
+ <Sparkles className="h-3.5 w-3.5" />
375
+ {product.totalSold}+ purchased
376
+ </span>
377
+ )}
378
+ </div>
379
+ <div className="flex flex-wrap gap-2">
380
+ <Button
381
+ size="sm"
382
+ onClick={() => router.push(`/products/${product.id}`)}
383
+ >
384
+ View details
385
+ </Button>
386
+ <Button
387
+ size="sm"
388
+ variant="outline"
389
+ onClick={() => handleRemoveFromWishlist(product.id)}
390
+ className="text-primary-600"
391
+ >
392
+ Remove
393
+ </Button>
394
+ </div>
395
+ </div>
396
+ </motion.div>
397
+ ))}
398
+ </AnimatePresence>
399
+ </motion.div>
400
+ )}
401
+ </>
402
+ )}
403
+
404
+ {isAuthenticated && emptyAfterFiltering && (
405
+ <div className="flex flex-col items-center justify-center rounded-2xl border border-dashed border-slate-200 bg-slate-50 p-12 text-center">
406
+ <div className="flex h-16 w-16 items-center justify-center rounded-full bg-slate-200 text-slate-500">
407
+ <Package className="h-8 w-8" />
408
+ </div>
409
+ <h3 className="mt-6 text-2xl font-semibold text-slate-900">
410
+ Nothing matches those filters
411
+ </h3>
412
+ <p className="mt-2 max-w-md text-sm text-slate-500">
413
+ Try showing out-of-stock items or adjust your sort order to revisit everything you’ve saved.
414
+ </p>
415
+ <Button className="mt-6" variant="outline" onClick={() => setOnlyInStock(false)}>
416
+ Show all saved products
417
+ </Button>
418
+ </div>
419
+ )}
420
+ </>
421
+ )}
422
+ </div>
423
+ </motion.div>
424
+ </div>
425
+ </div>
426
+ </div>
427
+ );
428
+ }
@@ -1,75 +0,0 @@
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
- import { ProductVariant } from './product-variant';
15
- /**
16
- *
17
- * @export
18
- * @interface InventoryPaginatedResponse
19
- */
20
- export interface InventoryPaginatedResponse {
21
- _id?: string;
22
- /**
23
- *
24
- * @type {string}
25
- * @memberof InventoryPaginatedResponse
26
- */
27
- storeId?: string;
28
- /**
29
- *
30
- * @type {ProductVariant}
31
- * @memberof InventoryPaginatedResponse
32
- */
33
- variant?: ProductVariant;
34
- /**
35
- *
36
- * @type {number}
37
- * @memberof InventoryPaginatedResponse
38
- */
39
- quantity?: number;
40
- /**
41
- *
42
- * @type {string}
43
- * @memberof InventoryPaginatedResponse
44
- */
45
- status?: InventoryPaginatedResponseStatusEnum;
46
- /**
47
- *
48
- * @type {number}
49
- * @memberof InventoryPaginatedResponse
50
- */
51
- total: number;
52
- /**
53
- *
54
- * @type {number}
55
- * @memberof InventoryPaginatedResponse
56
- */
57
- page: number;
58
- /**
59
- *
60
- * @type {number}
61
- * @memberof InventoryPaginatedResponse
62
- */
63
- limit: number;
64
- }
65
-
66
- /**
67
- * @export
68
- * @enum {string}
69
- */
70
- export enum InventoryPaginatedResponseStatusEnum {
71
- INSTOCK = 'IN_STOCK',
72
- OUTOFSTOCK = 'OUT_OF_STOCK',
73
- LOWSTOCK = 'LOW_STOCK'
74
- }
75
-
@@ -1,81 +0,0 @@
1
- import { authAdapter } from '@/lib/api-adapter';
2
- import { User, ApiResponse, LoginCredentials, RegisterData, AuthTokens } from '@/lib/types';
3
-
4
- export const authApi = {
5
- /**
6
- * Register a new user
7
- */
8
- async register(data: RegisterData): Promise<ApiResponse<{ user: User; tokens: AuthTokens }>> {
9
- const response = await authAdapter.register(data);
10
- return {
11
- ...response,
12
- data: {
13
- user: response.data.user,
14
- tokens: {
15
- accessToken: response.data.token,
16
- refreshToken: response.data.token, // Backend uses single token
17
- },
18
- },
19
- };
20
- },
21
-
22
- /**
23
- * Login user
24
- */
25
- async login(credentials: LoginCredentials): Promise<ApiResponse<{ user: User; tokens: AuthTokens }>> {
26
- const response = await authAdapter.login(credentials);
27
- return {
28
- ...response,
29
- data: {
30
- user: response.data.user,
31
- tokens: {
32
- accessToken: response.data.token,
33
- refreshToken: response.data.token, // Backend uses single token
34
- },
35
- },
36
- };
37
- },
38
-
39
- /**
40
- * Logout user
41
- */
42
- async logout(): Promise<void> {
43
- await authAdapter.logout();
44
- },
45
-
46
- /**
47
- * Get current user
48
- */
49
- async getCurrentUser(): Promise<ApiResponse<User>> {
50
- return await authAdapter.getCurrentUser();
51
- },
52
-
53
- /**
54
- * Update user profile
55
- */
56
- async updateProfile(data: Partial<User>): Promise<ApiResponse<User>> {
57
- return await authAdapter.updateProfile(data);
58
- },
59
-
60
- /**
61
- * Change password
62
- */
63
- async changePassword(currentPassword: string, newPassword: string): Promise<ApiResponse<void>> {
64
- return await authAdapter.changePassword(currentPassword, newPassword);
65
- },
66
-
67
- /**
68
- * Request password reset
69
- */
70
- async forgotPassword(email: string): Promise<ApiResponse<void>> {
71
- return await authAdapter.forgotPassword(email);
72
- },
73
-
74
- /**
75
- * Reset password with token
76
- */
77
- async resetPassword(token: string, newPassword: string): Promise<ApiResponse<void>> {
78
- return await authAdapter.resetPassword(token, newPassword);
79
- },
80
- };
81
-
@@ -1,42 +0,0 @@
1
- import { cartAdapter } from '@/lib/api-adapter';
2
- import { Cart, ApiResponse } from '@/lib/types';
3
-
4
- export const cartApi = {
5
- /**
6
- * Get user's cart
7
- */
8
- async getCart(): Promise<ApiResponse<Cart>> {
9
- return await cartAdapter.getCart();
10
- },
11
-
12
- /**
13
- * Add item to cart
14
- * Note: Backend uses product variants. If variant ID not provided, uses product ID as variant
15
- */
16
- async addToCart(productId: string, quantity: number = 1): Promise<ApiResponse<Cart>> {
17
- // Use product ID as variant ID for simplified products
18
- return await cartAdapter.addToCart(productId, productId, quantity);
19
- },
20
-
21
- /**
22
- * Update cart item quantity
23
- */
24
- async updateCartItem(productId: string, quantity: number): Promise<ApiResponse<Cart>> {
25
- return await cartAdapter.updateCartItem(productId, productId, quantity);
26
- },
27
-
28
- /**
29
- * Remove item from cart
30
- */
31
- async removeFromCart(productId: string): Promise<ApiResponse<Cart>> {
32
- return await cartAdapter.removeFromCart(productId, productId);
33
- },
34
-
35
- /**
36
- * Clear cart
37
- */
38
- async clearCart(): Promise<ApiResponse<void>> {
39
- return await cartAdapter.clearCart();
40
- },
41
- };
42
-