hey-pharmacist-ecommerce 1.0.4 → 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 -3865
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +6756 -3817
  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 -147
  73. package/src/lib/api-adapter/orders-adapter.ts +0 -195
  74. package/src/lib/api-adapter/products-adapter.ts +0 -194
@@ -1,86 +1,198 @@
1
1
  'use client';
2
2
 
3
- import React, { useState } from 'react';
4
- import { motion } from 'framer-motion';
5
- import { Package, ChevronLeft, ChevronRight } from 'lucide-react';
3
+ import React, { useEffect, useMemo, useRef, useState } from 'react';
4
+ import { AnimatePresence, motion } from 'framer-motion';
5
+ import { CalendarDays, ChevronLeft, ChevronRight, CreditCard, Filter, Package, Sparkles } from 'lucide-react';
6
6
  import { OrderCard } from '@/components/OrderCard';
7
7
  import { OrderCardSkeleton } from '@/components/ui/Skeleton';
8
8
  import { EmptyState } from '@/components/EmptyState';
9
9
  import { Button } from '@/components/ui/Button';
10
10
  import { useOrders } from '@/hooks/useOrders';
11
+ import { FilterChips } from '@/components/FilterChips';
11
12
  import { useRouter } from 'next/navigation';
13
+ import { ManualOrderDTOOrderStatusEnum, PaymentPaymentStatusEnum } from '@/lib/Apis';
14
+
15
+ const STATUS_FILTERS = ['All', ...Object.values(ManualOrderDTOOrderStatusEnum)];
16
+ const PAYMENT_FILTERS = ['All', ...Object.values(PaymentPaymentStatusEnum)];
17
+ type StatusFilterType = (typeof STATUS_FILTERS)[number];
18
+ type PaymentFilterType = (typeof PAYMENT_FILTERS)[number];
12
19
 
13
20
  export function OrdersScreen() {
14
21
  const router = useRouter();
15
22
  const [page, setPage] = useState(1);
16
- const { orders, isLoading, pagination } = useOrders(page, 10);
23
+ const [selectedFilter, setSelectedFilter] = useState<StatusFilterType>('All');
24
+ const [selectedPaymentFilter, setSelectedPaymentFilter] = useState<PaymentFilterType>('All');
25
+ const { orders, isLoading, pagination } = useOrders(
26
+ page,
27
+ 10,
28
+ selectedFilter,
29
+ selectedPaymentFilter
30
+ );
31
+ const [isOverflowOpen, setIsOverflowOpen] = useState(false);
32
+ const [filterSearchTerm, setFilterSearchTerm] = useState('');
33
+ const overflowMenuRef = useRef<HTMLDivElement | null>(null);
34
+
35
+ const filteredOrders = useMemo(() => {
36
+ return orders.filter((order) => {
37
+ const matchesStatus =
38
+ selectedFilter === 'All' ||
39
+ order?.orderStatus?.toLowerCase() === selectedFilter.toLowerCase();
40
+ const matchesPayment =
41
+ selectedPaymentFilter === 'All' ||
42
+ order?.payment?.paymentStatus?.toLowerCase() === selectedPaymentFilter.toLowerCase();
43
+
44
+ return matchesStatus && matchesPayment;
45
+ });
46
+ }, [orders, selectedFilter, selectedPaymentFilter]);
47
+
48
+ const hasOrders = filteredOrders.length > 0;
49
+ const MAX_VISIBLE_FILTERS = 4;
50
+
51
+ // Removed local overflow/search logic in favor of reusable FilterChips
52
+
53
+ useEffect(() => {
54
+ if (!isOverflowOpen) {
55
+ setFilterSearchTerm('');
56
+ }
57
+ }, [isOverflowOpen]);
58
+
59
+ useEffect(() => {
60
+ function handleClickOutside(event: MouseEvent) {
61
+ if (overflowMenuRef.current && !overflowMenuRef.current.contains(event.target as Node)) {
62
+ setIsOverflowOpen(false);
63
+ }
64
+ }
65
+
66
+ if (isOverflowOpen) {
67
+ document.addEventListener('mousedown', handleClickOutside);
68
+ }
69
+
70
+ return () => {
71
+ document.removeEventListener('mousedown', handleClickOutside);
72
+ };
73
+ }, [isOverflowOpen]);
17
74
 
18
75
  return (
19
- <div className="min-h-screen bg-gray-50 py-12">
20
- <div className="container mx-auto px-4 max-w-5xl">
21
- {/* Header */}
22
- <motion.div
23
- initial={{ opacity: 0, y: 20 }}
24
- animate={{ opacity: 1, y: 0 }}
25
- className="mb-8"
26
- >
27
- <h1 className="text-4xl font-bold text-gray-900 mb-2">Order History</h1>
28
- <p className="text-gray-600">
29
- View and manage all your past orders
30
- </p>
31
- </motion.div>
32
-
33
- {/* Orders List */}
34
- {isLoading ? (
35
- <div className="space-y-4">
36
- {Array.from({ length: 3 }).map((_, i) => (
37
- <OrderCardSkeleton key={i} />
38
- ))}
39
- </div>
40
- ) : orders.length > 0 ? (
41
- <>
42
- <div className="space-y-4 mb-8">
43
- {orders.map((order) => (
44
- <OrderCard key={order.id} order={order} />
45
- ))}
76
+ <div className="min-h-screen bg-slate-50">
77
+ <section className="relative overflow-hidden bg-gradient-to-br from-[rgb(var(--header-from))] via-[rgb(var(--header-via))] to-[rgb(var(--header-to))] text-white mb-8">
78
+ <div className="absolute inset-0 bg-[radial-gradient(circle_at_top_left,_rgba(255,255,255,0.35),_transparent_60%)]" />
79
+ <div className="relative container mx-auto px-4 py-16">
80
+ <motion.div
81
+ initial={{ opacity: 0, y: 24 }}
82
+ animate={{ opacity: 1, y: 0 }}
83
+ className="space-y-6"
84
+ >
85
+ <span className="inline-flex items-center gap-2 rounded-full bg-white/15 px-3 py-1 text-sm font-semibold uppercase tracking-[0.35em] text-white/70 backdrop-blur">
86
+ <CalendarDays className="h-4 w-4" />
87
+ Order history
88
+ </span>
89
+ <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
90
+ <div className="space-y-4">
91
+ <h1 className="text-4xl font-bold md:text-5xl">All of your pharmacy orders</h1>
92
+ <p className="max-w-2xl text-white/80 md:text-lg">
93
+ Access receipts, shipping statuses, and reorder suggestions in one organized
94
+ timeline curated by our pharmacists.
95
+ </p>
96
+ </div>
97
+ <div className="rounded-3xl bg-white/15 p-6 backdrop-blur">
98
+ <p className="text-sm font-semibold uppercase tracking-[0.35em] text-white/70">
99
+ Quick tip
100
+ </p>
101
+ <p className="mt-3 text-sm text-white/80">
102
+ Use filters to review previous prescriptions, reorder favorites, or download
103
+ invoices for insurance claims.
104
+ </p>
105
+ </div>
106
+ </div>
107
+ </motion.div>
108
+ </div>
109
+ </section>
110
+
111
+ <div className="relative -mt-16 pb-16 container mx-auto px-4">
112
+ <div className="container mx-auto px-4">
113
+ <motion.div
114
+ initial={{ opacity: 0, y: 24 }}
115
+ animate={{ opacity: 1, y: 0 }}
116
+ className="rounded-3xl border border-slate-100 bg-white p-6 shadow-lg shadow-primary-50"
117
+ >
118
+ <div className="flex flex-col gap-4 md:flex-row md:items-center md:justify-between">
119
+ <div className="flex items-center gap-3 text-sm text-slate-500">
120
+ <Sparkles className="h-4 w-4 text-primary-500" />
121
+ <span>Explore your complete order archive with pharmacist notes.</span>
122
+ </div>
123
+ <div className="flex flex-col gap-4 md:items-end">
124
+ <FilterChips
125
+ label="Status filters"
126
+ icon={Filter}
127
+ filters={STATUS_FILTERS}
128
+ selected={selectedFilter}
129
+ onSelect={(value) => {
130
+ setSelectedFilter(value as any);
131
+ setPage(1);
132
+ }}
133
+ maxVisible={MAX_VISIBLE_FILTERS}
134
+ variant="primary"
135
+ />
136
+
137
+ <FilterChips
138
+ label="Payment status"
139
+ icon={CreditCard}
140
+ filters={PAYMENT_FILTERS}
141
+ selected={selectedPaymentFilter}
142
+ onSelect={(value) => {
143
+ setSelectedPaymentFilter(value as any);
144
+ setPage(1);
145
+ }}
146
+ maxVisible={MAX_VISIBLE_FILTERS}
147
+ variant="primary"
148
+ />
149
+ </div>
46
150
  </div>
47
151
 
48
- {/* Pagination */}
49
- {pagination.totalPages > 1 && (
50
- <div className="flex justify-center items-center gap-4">
152
+ <div className="mt-6 space-y-4">
153
+ {isLoading ? (
154
+ Array.from({ length: 3 }).map((_, index) => <OrderCardSkeleton key={index} />)
155
+ ) : hasOrders ? (
156
+ filteredOrders.map((order) => <OrderCard key={order.id} order={order} />)
157
+ ) : (
158
+ <EmptyState
159
+ icon={Package}
160
+ title="No orders found for these filters"
161
+ description="Adjust the status or payment filters, or browse the shop for new essentials."
162
+ actionLabel="Shop products"
163
+ onAction={() => router.push('/shop')}
164
+ />
165
+ )}
166
+ </div>
167
+
168
+ {!isLoading && pagination.totalPages > 1 && hasOrders && (
169
+ <div className="mt-10 flex flex-wrap items-center justify-center gap-4">
51
170
  <Button
52
171
  variant="outline"
53
- onClick={() => setPage(page - 1)}
172
+ onClick={() => setPage((current) => Math.max(1, current - 1))}
54
173
  disabled={page === 1}
55
174
  >
56
- <ChevronLeft className="w-5 h-5" />
175
+ <ChevronLeft className="h-5 w-5" />
57
176
  Previous
58
177
  </Button>
59
- <span className="text-gray-700">
178
+ <span className="text-sm font-semibold text-slate-600">
60
179
  Page {page} of {pagination.totalPages}
61
180
  </span>
62
181
  <Button
63
182
  variant="outline"
64
- onClick={() => setPage(page + 1)}
183
+ onClick={() =>
184
+ setPage((current) => Math.min(pagination.totalPages, current + 1))
185
+ }
65
186
  disabled={page === pagination.totalPages}
66
187
  >
67
188
  Next
68
- <ChevronRight className="w-5 h-5" />
189
+ <ChevronRight className="h-5 w-5" />
69
190
  </Button>
70
191
  </div>
71
192
  )}
72
- </>
73
- ) : (
74
- <EmptyState
75
- icon={Package}
76
- title="No orders yet"
77
- description="Start shopping and your orders will appear here"
78
- actionLabel="Start Shopping"
79
- onAction={() => router.push('/shop')}
80
- />
81
- )}
193
+ </motion.div>
194
+ </div>
82
195
  </div>
83
196
  </div>
84
197
  );
85
198
  }
86
-