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
@@ -5,19 +5,30 @@ import { motion } from 'framer-motion';
5
5
  import { useForm } from 'react-hook-form';
6
6
  import { zodResolver } from '@hookform/resolvers/zod';
7
7
  import { z } from 'zod';
8
- import { User, Mail, Phone, LogOut, Package, Heart } from 'lucide-react';
8
+ import Link from 'next/link';
9
+ import { useRouter } from 'next/navigation';
10
+ import {
11
+ Heart,
12
+ HeartPulse,
13
+ LogOut,
14
+ Mail,
15
+ MapPin,
16
+ Package,
17
+ Phone,
18
+ ShieldCheck,
19
+ Sparkles,
20
+ User,
21
+ } from 'lucide-react';
9
22
  import { Button } from '@/components/ui/Button';
10
23
  import { Input } from '@/components/ui/Input';
11
24
  import { useAuth } from '@/providers/AuthProvider';
12
- import { useRouter } from 'next/navigation';
13
25
  import { toast } from 'sonner';
14
26
  import { getInitials } from '@/lib/utils/format';
15
- import Link from 'next/link';
16
27
 
17
28
  const profileSchema = z.object({
18
29
  firstName: z.string().min(2, 'First name is required'),
19
30
  lastName: z.string().min(2, 'Last name is required'),
20
- email: z.string().email('Invalid email address'),
31
+ email: z.string().email('Enter a valid email address'),
21
32
  phone: z.string().optional(),
22
33
  });
23
34
 
@@ -35,10 +46,10 @@ export function ProfileScreen() {
35
46
  } = useForm<ProfileFormData>({
36
47
  resolver: zodResolver(profileSchema),
37
48
  defaultValues: {
38
- firstName: user?.firstName || '',
39
- lastName: user?.lastName || '',
49
+ firstName: user?.firstname || '',
50
+ lastName: user?.lastname || '',
40
51
  email: user?.email || '',
41
- phone: user?.phone || '',
52
+ phone: user?.phoneNumber || '',
42
53
  },
43
54
  });
44
55
 
@@ -65,147 +76,212 @@ export function ProfileScreen() {
65
76
  return null;
66
77
  }
67
78
 
68
- const menuItems = [
79
+ const quickLinks = [
69
80
  {
70
81
  icon: Package,
71
- label: 'My Orders',
82
+ label: 'Order history',
83
+ description: 'Track shipments and download invoices',
72
84
  href: '/orders',
73
- description: 'View and track your orders',
74
85
  },
75
86
  {
76
87
  icon: Heart,
77
88
  label: 'Wishlist',
89
+ description: 'Curate go-to remedies and favorites',
78
90
  href: '/wishlist',
79
- description: 'Your saved products',
91
+ },
92
+ {
93
+ icon: MapPin,
94
+ label: 'Delivery addresses',
95
+ description: 'Manage saved delivery locations',
96
+ href: '/account/addresses',
80
97
  },
81
98
  ];
82
99
 
83
100
  return (
84
- <div className="min-h-screen bg-gray-50 py-12">
85
- <div className="container mx-auto px-4 max-w-4xl">
86
- {/* Header */}
87
- <motion.div
88
- initial={{ opacity: 0, y: 20 }}
89
- animate={{ opacity: 1, y: 0 }}
90
- className="mb-8"
91
- >
92
- <h1 className="text-4xl font-bold text-gray-900 mb-2">My Account</h1>
93
- <p className="text-gray-600">Manage your profile and preferences</p>
94
- </motion.div>
95
-
96
- <div className="grid md:grid-cols-3 gap-8">
97
- {/* Sidebar */}
98
- <div className="md:col-span-1">
101
+ <div className="min-h-screen bg-slate-50">
102
+ <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">
103
+ <div className="absolute inset-0 bg-[radial-gradient(circle_at_top_left,_rgba(255,255,255,0.35),_transparent_60%)]" />
104
+ <div className="relative container mx-auto px-4 py-16">
105
+ <motion.div
106
+ initial={{ opacity: 0, y: 24 }}
107
+ animate={{ opacity: 1, y: 0 }}
108
+ className="flex flex-col gap-8 md:flex-row md:items-center md:justify-between"
109
+ >
110
+ <div className="space-y-5">
111
+ <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">
112
+ <HeartPulse className="h-4 w-4" />
113
+ My account
114
+ </span>
115
+ <h1 className="text-4xl font-bold md:text-5xl">
116
+ Hello, {user.firstname} {user.lastname}
117
+ </h1>
118
+ <p className="max-w-2xl text-white/80 md:text-lg">
119
+ Manage profile details, shipping preferences, and personalized recommendations. Our
120
+ pharmacists keep your care plan up to date.
121
+ </p>
122
+ <div className="flex flex-wrap items-center gap-4 text-sm text-white/80">
123
+ <span className="inline-flex items-center gap-2 rounded-full bg-white/15 px-4 py-2">
124
+ <ShieldCheck className="h-4 w-4" />
125
+ Account secured with multi-factor ready login
126
+ </span>
127
+ </div>
128
+ </div>
129
+ <div className="flex flex-col items-center gap-4 rounded-3xl bg-white/15 p-6 text-center backdrop-blur">
130
+ <div className="flex h-24 w-24 items-center justify-center rounded-full bg-white/20 text-3xl font-bold text-white">
131
+ {getInitials(user?.firstname || '', user?.lastname || '') || ''}
132
+ </div>
133
+ <p className="text-sm text-white/80">{user.email}</p>
134
+ <Button
135
+ variant="ghost"
136
+ className="text-white hover:bg-white/20"
137
+ onClick={() => router.push('/account/change-password')}
138
+ >
139
+ Change password
140
+ </Button>
141
+ </div>
142
+ </motion.div>
143
+ </div>
144
+ </section>
145
+
146
+ <div className="relative -mt-16 pb-20">
147
+ <div className="container mx-auto px-4">
148
+ <div className="grid gap-10 lg:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)]">
99
149
  <motion.div
100
- initial={{ opacity: 0, y: 20 }}
150
+ initial={{ opacity: 0, y: 24 }}
101
151
  animate={{ opacity: 1, y: 0 }}
102
- transition={{ delay: 0.1 }}
103
- className="bg-white rounded-2xl p-6 shadow-sm"
152
+ className="space-y-6"
104
153
  >
105
- {/* Avatar */}
106
- <div className="flex flex-col items-center mb-6">
107
- <div className="w-24 h-24 bg-gradient-to-br from-primary-500 to-secondary-500 rounded-full flex items-center justify-center text-white text-3xl font-bold mb-4">
108
- {getInitials(user.firstName, user.lastName)}
154
+ <section className="rounded-3xl border border-slate-100 bg-white p-8 shadow-lg shadow-primary-50">
155
+ <div className="flex items-center justify-between">
156
+ <h2 className="text-xl font-semibold text-slate-900">
157
+ Personal information
158
+ </h2>
159
+ <Sparkles className="h-5 w-5 text-primary-500" />
109
160
  </div>
110
- <h3 className="text-xl font-bold text-gray-900">
111
- {user.firstName} {user.lastName}
112
- </h3>
113
- <p className="text-gray-600">{user.email}</p>
114
- </div>
115
161
 
116
- {/* Menu Items */}
117
- <nav className="space-y-2">
118
- {menuItems.map((item) => (
162
+ <form onSubmit={handleSubmit(onSubmit)} className="mt-6 space-y-6">
163
+ <div className="grid gap-4 md:grid-cols-2">
164
+ <Input
165
+ label="First name"
166
+ placeholder="Taylor"
167
+ {...register('firstName')}
168
+ error={errors.firstName?.message}
169
+ />
170
+ <Input
171
+ label="Last name"
172
+ placeholder="Reed"
173
+ {...register('lastName')}
174
+ error={errors.lastName?.message}
175
+ />
176
+ </div>
177
+
178
+ <div className="relative">
179
+ <Input
180
+ type="email"
181
+ label="Email address"
182
+ placeholder="you@example.com"
183
+ className="pl-10"
184
+ {...register('email')}
185
+ error={errors.email?.message}
186
+ />
187
+ <Mail className="absolute left-3 top-[38px] h-4 w-4 text-slate-400" />
188
+ </div>
189
+
190
+ <div className="relative">
191
+ <Input
192
+ type="tel"
193
+ label="Phone number"
194
+ placeholder="+1 (555) 123-4567"
195
+ className="pl-10"
196
+ {...register('phone')}
197
+ error={errors.phone?.message}
198
+ />
199
+ <Phone className="absolute left-3 top-[38px] h-4 w-4 text-slate-400" />
200
+ </div>
201
+
202
+ <div className="flex flex-wrap gap-4">
203
+ <Button
204
+ type="submit"
205
+ size="lg"
206
+ isLoading={isSubmitting}
207
+ >
208
+ Save changes
209
+ </Button>
210
+ <Button
211
+ type="button"
212
+ variant="outline"
213
+ size="lg"
214
+ onClick={() => router.push('/orders')}
215
+ >
216
+ View recent orders
217
+ </Button>
218
+ </div>
219
+ </form>
220
+ </section>
221
+
222
+ <section className="grid gap-4 md:grid-cols-2">
223
+ {quickLinks.map((item) => (
119
224
  <Link
120
225
  key={item.href}
121
226
  href={item.href}
122
- className="flex items-start gap-3 p-3 rounded-lg hover:bg-gray-50 transition-colors group"
227
+ className="group rounded-3xl border border-slate-100 bg-white p-6 shadow-sm transition hover:-translate-y-1 hover:shadow-lg"
123
228
  >
124
- <item.icon className="w-5 h-5 text-gray-500 group-hover:text-primary-600 mt-0.5" />
125
- <div>
126
- <p className="font-medium text-gray-900 group-hover:text-primary-600">
127
- {item.label}
128
- </p>
129
- <p className="text-sm text-gray-500">{item.description}</p>
229
+ <div className="flex items-center gap-3">
230
+ <span className="rounded-2xl bg-primary-50 p-3 text-primary-600">
231
+ <item.icon className="h-5 w-5" />
232
+ </span>
233
+ <div>
234
+ <p className="text-base font-semibold text-slate-900 group-hover:text-primary-600">
235
+ {item.label}
236
+ </p>
237
+ <p className="text-sm text-slate-500">{item.description}</p>
238
+ </div>
130
239
  </div>
131
240
  </Link>
132
241
  ))}
133
- </nav>
134
-
135
- {/* Logout Button */}
136
- <button
137
- onClick={handleLogout}
138
- className="w-full mt-6 flex items-center justify-center gap-2 p-3 text-red-600 hover:bg-red-50 rounded-lg transition-colors font-medium"
139
- >
140
- <LogOut className="w-5 h-5" />
141
- Logout
142
- </button>
242
+ </section>
143
243
  </motion.div>
144
- </div>
145
244
 
146
- {/* Main Content */}
147
- <div className="md:col-span-2">
148
- <motion.div
149
- initial={{ opacity: 0, y: 20 }}
245
+ <motion.aside
246
+ initial={{ opacity: 0, y: 24 }}
150
247
  animate={{ opacity: 1, y: 0 }}
151
- transition={{ delay: 0.2 }}
152
- className="bg-white rounded-2xl p-8 shadow-sm"
248
+ transition={{ delay: 0.1 }}
249
+ className="space-y-6"
153
250
  >
154
- <h2 className="text-2xl font-bold text-gray-900 mb-6">
155
- Personal Information
156
- </h2>
157
-
158
- <form onSubmit={handleSubmit(onSubmit)} className="space-y-6">
159
- <div className="grid grid-cols-2 gap-4">
160
- <Input
161
- label="First Name"
162
- {...register('firstName')}
163
- error={errors.firstName?.message}
164
- />
165
- <Input
166
- label="Last Name"
167
- {...register('lastName')}
168
- error={errors.lastName?.message}
169
- />
170
- </div>
251
+ <div className="rounded-3xl border border-slate-100 bg-white p-6 shadow-lg shadow-primary-50">
252
+ <h3 className="text-lg font-semibold text-slate-900">Care preferences</h3>
253
+ <p className="mt-3 text-sm text-slate-600">
254
+ Customize how we support you. Set refill reminders or manage communication
255
+ preferences to stay aligned with your wellness goals.
256
+ </p>
257
+ <Button
258
+ variant="outline"
259
+ className="mt-4 w-full"
260
+ onClick={() => router.push('/account/preferences')}
261
+ >
262
+ Manage preferences
263
+ </Button>
264
+ </div>
171
265
 
172
- <Input
173
- type="email"
174
- label="Email Address"
175
- {...register('email')}
176
- error={errors.email?.message}
177
- />
178
-
179
- <Input
180
- type="tel"
181
- label="Phone Number"
182
- {...register('phone')}
183
- error={errors.phone?.message}
184
- />
185
-
186
- <div className="flex gap-4">
187
- <Button
188
- type="submit"
189
- size="lg"
190
- isLoading={isSubmitting}
191
- >
192
- Save Changes
193
- </Button>
194
- <Button
195
- type="button"
196
- variant="outline"
197
- size="lg"
198
- onClick={() => router.push('/account/change-password')}
199
- >
200
- Change Password
201
- </Button>
202
- </div>
203
- </form>
204
- </motion.div>
266
+ <div className="rounded-3xl border border-primary-100 bg-primary-50/70 p-6 text-sm text-primary-700 shadow-sm">
267
+ <p className="font-semibold uppercase tracking-[0.3em]">Pharmacist tip</p>
268
+ <p className="mt-3 leading-relaxed">
269
+ Keep your phone number current so pharmacists can reach you quickly with dosage
270
+ advice or time-sensitive updates about your order.
271
+ </p>
272
+ </div>
273
+
274
+ <button
275
+ onClick={handleLogout}
276
+ className="flex w-full items-center justify-center gap-2 rounded-3xl border border-red-200 bg-red-50 px-4 py-3 text-sm font-semibold text-red-600 transition hover:bg-red-100"
277
+ >
278
+ <LogOut className="h-4 w-4" />
279
+ Log out
280
+ </button>
281
+ </motion.aside>
205
282
  </div>
206
283
  </div>
207
284
  </div>
208
285
  </div>
209
286
  );
210
287
  }
211
-