hey-pharmacist-ecommerce 1.1.15 → 1.1.17
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/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +585 -248
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +585 -248
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/screens/ProfileScreen.tsx +74 -234
- package/src/screens/ShopScreen.tsx +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hey-pharmacist-ecommerce",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.17",
|
|
4
4
|
"description": "Production-ready, multi-tenant e‑commerce UI + API adapter for Next.js with auth, carts, checkout, orders, theming, and pharmacist-focused UX.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,7 @@ export { CartScreen } from './screens/CartScreen';
|
|
|
15
15
|
export { CheckoutScreen } from './screens/CheckoutScreen';
|
|
16
16
|
export { LoginScreen } from './screens/LoginScreen';
|
|
17
17
|
export { RegisterScreen } from './screens/RegisterScreen';
|
|
18
|
-
export { ProfileScreen } from './screens/ProfileScreen';
|
|
18
|
+
export { default as ProfileScreen } from './screens/ProfileScreen';
|
|
19
19
|
export { OrdersScreen } from './screens/OrdersScreen';
|
|
20
20
|
export { CurrentOrdersScreen } from './screens/CurrentOrdersScreen';
|
|
21
21
|
export { AddressesScreen } from './screens/AddressesScreen';
|
|
@@ -1,42 +1,63 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import React, { useState } from 'react';
|
|
4
|
-
import { motion } from 'framer-motion';
|
|
5
|
-
import Link from 'next/link';
|
|
6
4
|
import { useRouter } from 'next/navigation';
|
|
7
5
|
import {
|
|
8
|
-
|
|
6
|
+
User,
|
|
7
|
+
Package,
|
|
9
8
|
Heart,
|
|
10
|
-
|
|
11
|
-
LogOut,
|
|
12
|
-
Mail,
|
|
9
|
+
CreditCard,
|
|
13
10
|
MapPin,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
Sparkles,
|
|
18
|
-
User,
|
|
11
|
+
Settings,
|
|
12
|
+
LogOut,
|
|
13
|
+
ChevronDown,
|
|
19
14
|
} from 'lucide-react';
|
|
20
|
-
import { Button } from '@/components/ui/Button';
|
|
21
15
|
import { useAuth } from '@/providers/AuthProvider';
|
|
22
|
-
import { getInitials } from '@/lib/utils/format';
|
|
23
16
|
import { useBasePath } from '@/providers/BasePathProvider';
|
|
17
|
+
import { getInitials } from '@/lib/utils/format';
|
|
18
|
+
import { TabNavigation } from '@/components/TabNavigation';
|
|
19
|
+
import { AccountOverviewTab } from '@/components/AccountOverviewTab';
|
|
20
|
+
import { AccountOrdersTab } from '@/components/AccountOrdersTab';
|
|
21
|
+
import { AccountSavedItemsTab } from '@/components/AccountSavedItemsTab';
|
|
22
|
+
import { AccountPaymentTab } from '@/components/AccountPaymentTab';
|
|
23
|
+
import { AccountAddressesTab } from '@/components/AccountAddressesTab';
|
|
24
|
+
import { AccountSettingsTab } from '@/components/AccountSettingsTab';
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
const tabs = [
|
|
27
|
+
{ id: 'overview', label: 'Overview', icon: User },
|
|
28
|
+
{ id: 'orders', label: 'Orders', icon: Package },
|
|
29
|
+
{ id: 'saved-items', label: 'Saved Items', icon: Heart },
|
|
30
|
+
// { id: 'payment', label: 'Payment', icon: CreditCard },
|
|
31
|
+
{ id: 'addresses', label: 'Addresses', icon: MapPin },
|
|
32
|
+
{ id: 'settings', label: 'Settings', icon: Settings },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export default function AccountPage() {
|
|
26
36
|
const router = useRouter();
|
|
27
37
|
const { user, logout, isLoading } = useAuth();
|
|
28
38
|
const { buildPath } = useBasePath();
|
|
39
|
+
const [activeTab, setActiveTab] = useState('overview');
|
|
40
|
+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
|
29
41
|
const [isLoggingOut, setIsLoggingOut] = useState(false);
|
|
30
|
-
|
|
42
|
+
|
|
43
|
+
// Listen for tab switch events from child components
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
const handleTabSwitch = (event: CustomEvent) => {
|
|
46
|
+
setActiveTab(event.detail);
|
|
47
|
+
};
|
|
48
|
+
window.addEventListener('switchTab', handleTabSwitch as EventListener);
|
|
49
|
+
return () => {
|
|
50
|
+
window.removeEventListener('switchTab', handleTabSwitch as EventListener);
|
|
51
|
+
};
|
|
52
|
+
}, []);
|
|
31
53
|
|
|
32
54
|
const handleLogout = async () => {
|
|
33
55
|
setIsLoggingOut(true);
|
|
34
|
-
setLogoutError(null);
|
|
35
56
|
try {
|
|
36
57
|
await logout();
|
|
37
58
|
router.push(buildPath('/'));
|
|
38
59
|
} catch (error: any) {
|
|
39
|
-
|
|
60
|
+
console.error('Logout failed:', error);
|
|
40
61
|
} finally {
|
|
41
62
|
setIsLoggingOut(false);
|
|
42
63
|
}
|
|
@@ -48,230 +69,49 @@ export function ProfileScreen() {
|
|
|
48
69
|
return null;
|
|
49
70
|
}
|
|
50
71
|
|
|
51
|
-
const
|
|
52
|
-
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
},
|
|
70
|
-
];
|
|
72
|
+
const renderTabContent = () => {
|
|
73
|
+
switch (activeTab) {
|
|
74
|
+
case 'overview':
|
|
75
|
+
return <AccountOverviewTab />;
|
|
76
|
+
case 'orders':
|
|
77
|
+
return <AccountOrdersTab />;
|
|
78
|
+
case 'saved-items':
|
|
79
|
+
return <AccountSavedItemsTab />;
|
|
80
|
+
// case 'payment':
|
|
81
|
+
// return <AccountPaymentTab />;
|
|
82
|
+
case 'addresses':
|
|
83
|
+
return <AccountAddressesTab />;
|
|
84
|
+
case 'settings':
|
|
85
|
+
return <AccountSettingsTab />;
|
|
86
|
+
default:
|
|
87
|
+
return <AccountOverviewTab />;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
71
90
|
|
|
72
91
|
return (
|
|
73
|
-
<div className="min-h-screen bg-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
<ShieldCheck className="mt-[1px] h-4 w-4 text-red-500" />
|
|
84
|
-
<span>{logoutError}</span>
|
|
85
|
-
</div>
|
|
86
|
-
)}
|
|
87
|
-
<Button
|
|
88
|
-
type="button"
|
|
89
|
-
variant="outline"
|
|
90
|
-
size="sm"
|
|
91
|
-
className="border-red-200 text-red-600 hover:bg-red-50"
|
|
92
|
-
onClick={handleLogout}
|
|
93
|
-
disabled={isLoggingOut}
|
|
94
|
-
>
|
|
95
|
-
<LogOut className="h-4 w-4" />
|
|
96
|
-
{isLoggingOut ? 'Logging out...' : 'Log out'}
|
|
97
|
-
</Button>
|
|
98
|
-
</div>
|
|
99
|
-
</div>
|
|
100
|
-
<motion.div
|
|
101
|
-
initial={{ opacity: 0, y: 18 }}
|
|
102
|
-
animate={{ opacity: 1, y: 0 }}
|
|
103
|
-
className="grid gap-8 md:grid-cols-[minmax(0,1.1fr)_minmax(0,0.9fr)] md:items-center"
|
|
104
|
-
>
|
|
105
|
-
<div className="space-y-4">
|
|
106
|
-
<div className="inline-flex items-center gap-2 rounded-full bg-slate-900 text-white px-4 py-1 text-xs font-semibold uppercase tracking-[0.32em]">
|
|
107
|
-
<HeartPulse className="h-4 w-4" />
|
|
108
|
-
Account
|
|
109
|
-
</div>
|
|
110
|
-
<div>
|
|
111
|
-
<h1 className="text-4xl font-semibold md:text-5xl">
|
|
112
|
-
Welcome back, {user.firstname} {user.lastname}
|
|
113
|
-
</h1>
|
|
114
|
-
<p className="mt-3 max-w-2xl text-base text-slate-600">
|
|
115
|
-
Keep your identity and delivery details accurate for smoother refills, faster
|
|
116
|
-
shipping, and timely pharmacist guidance.
|
|
117
|
-
</p>
|
|
118
|
-
</div>
|
|
119
|
-
<div className="flex flex-wrap gap-3 text-sm text-slate-600">
|
|
120
|
-
<span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-2">
|
|
121
|
-
<ShieldCheck className="h-4 w-4 text-primary-600" />
|
|
122
|
-
Secure login enabled
|
|
123
|
-
</span>
|
|
124
|
-
<span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-2">
|
|
125
|
-
<Mail className="h-4 w-4 text-primary-600" />
|
|
126
|
-
{user.email}
|
|
127
|
-
</span>
|
|
128
|
-
<span className="inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-2">
|
|
129
|
-
<Phone className="h-4 w-4 text-primary-600" />
|
|
130
|
-
{user.phoneNumber || 'Add phone for urgent updates'}
|
|
131
|
-
</span>
|
|
132
|
-
</div>
|
|
92
|
+
<div className="min-h-screen bg-gradient-to-b from-[#F8FAFC] to-[#EBF4FB]">
|
|
93
|
+
{/* Header */}
|
|
94
|
+
<div className="">
|
|
95
|
+
<div className="container mx-auto px-4 py-4">
|
|
96
|
+
<div className="flex items-center justify-between">
|
|
97
|
+
<div>
|
|
98
|
+
<h1 className="text-2xl font-semibold text-secondary">My Account</h1>
|
|
99
|
+
<p className="text-sm text-muted">
|
|
100
|
+
Manage your profile, orders, and preferences
|
|
101
|
+
</p>
|
|
133
102
|
</div>
|
|
134
103
|
|
|
135
|
-
|
|
136
|
-
<div className="flex items-center gap-4">
|
|
137
|
-
<div className="flex h-16 w-16 items-center justify-center rounded-2xl bg-white text-2xl font-semibold text-slate-900 shadow-sm">
|
|
138
|
-
{getInitials(user?.firstname || '', user?.lastname || '') || ''}
|
|
139
|
-
</div>
|
|
140
|
-
<div className="space-y-1">
|
|
141
|
-
<p className="text-sm text-slate-500">Signed in as</p>
|
|
142
|
-
<p className="text-lg font-semibold text-slate-900">{user.firstname}</p>
|
|
143
|
-
<p className="text-sm text-slate-500">{user.email}</p>
|
|
144
|
-
</div>
|
|
145
|
-
</div>
|
|
146
|
-
<div className="grid gap-3 sm:grid-cols-2">
|
|
147
|
-
<Button
|
|
148
|
-
variant="outline"
|
|
149
|
-
size="md"
|
|
150
|
-
className="border-slate-300 text-slate-800 hover:bg-white"
|
|
151
|
-
onClick={() => router.push(buildPath('/account/edit'))}
|
|
152
|
-
>
|
|
153
|
-
Edit profile
|
|
154
|
-
</Button>
|
|
155
|
-
<Button
|
|
156
|
-
variant="ghost"
|
|
157
|
-
size="md"
|
|
158
|
-
className="text-slate-700 hover:bg-white"
|
|
159
|
-
onClick={() => router.push(buildPath('/account/change-password'))}
|
|
160
|
-
>
|
|
161
|
-
Change password
|
|
162
|
-
</Button>
|
|
163
|
-
</div>
|
|
164
|
-
</div>
|
|
165
|
-
</motion.div>
|
|
104
|
+
</div>
|
|
166
105
|
</div>
|
|
106
|
+
</div>
|
|
167
107
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
initial={{ opacity: 0, y: 18 }}
|
|
171
|
-
animate={{ opacity: 1, y: 0 }}
|
|
172
|
-
className="space-y-6"
|
|
173
|
-
>
|
|
174
|
-
<section className="rounded-3xl border border-slate-200 bg-white p-7 shadow-lg shadow-primary-50/40 min-h-[420px] h-full flex flex-col">
|
|
175
|
-
<div className="flex items-center justify-between gap-3">
|
|
176
|
-
<div>
|
|
177
|
-
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-slate-400">
|
|
178
|
-
Essentials
|
|
179
|
-
</p>
|
|
180
|
-
<h2 className="mt-1 text-xl font-semibold text-slate-900">Profile snapshot</h2>
|
|
181
|
-
</div>
|
|
182
|
-
<Sparkles className="h-5 w-5 text-primary-500" />
|
|
183
|
-
</div>
|
|
184
|
-
<div className="mt-6 grid gap-4 md:grid-cols-2">
|
|
185
|
-
<div className="rounded-2xl border border-slate-200 bg-slate-50/70 p-5">
|
|
186
|
-
<p className="text-xs font-semibold uppercase tracking-[0.28em] text-slate-500">
|
|
187
|
-
Contact
|
|
188
|
-
</p>
|
|
189
|
-
<div className="mt-3 space-y-2 text-sm text-slate-600">
|
|
190
|
-
<p className="flex items-center gap-2 font-semibold text-slate-900">
|
|
191
|
-
<User className="h-4 w-4 text-primary-500" />
|
|
192
|
-
{user.firstname} {user.lastname}
|
|
193
|
-
</p>
|
|
194
|
-
<p className="flex items-center gap-2">
|
|
195
|
-
<Mail className="h-4 w-4 text-primary-500" />
|
|
196
|
-
{user.email}
|
|
197
|
-
</p>
|
|
198
|
-
<p className="flex items-center gap-2">
|
|
199
|
-
<Phone className="h-4 w-4 text-primary-500" />
|
|
200
|
-
{user.phoneNumber || 'Not provided'}
|
|
201
|
-
</p>
|
|
202
|
-
</div>
|
|
203
|
-
<Button
|
|
204
|
-
variant="outline"
|
|
205
|
-
size="md"
|
|
206
|
-
className="mt-4 w-full border-slate-300 text-slate-800 hover:bg-white"
|
|
207
|
-
onClick={() => router.push(buildPath('/account/edit'))}
|
|
208
|
-
>
|
|
209
|
-
Update information
|
|
210
|
-
</Button>
|
|
211
|
-
</div>
|
|
212
|
-
|
|
213
|
-
<div className="rounded-2xl border border-slate-200 bg-slate-50/70 p-5">
|
|
214
|
-
<p className="text-xs font-semibold uppercase tracking-[0.28em] text-slate-500">
|
|
215
|
-
Security
|
|
216
|
-
</p>
|
|
217
|
-
<div className="mt-3 space-y-2 text-sm text-slate-600">
|
|
218
|
-
<p className="flex items-center gap-2 font-semibold text-slate-900">
|
|
219
|
-
<ShieldCheck className="h-4 w-4 text-primary-500" />
|
|
220
|
-
Multi-factor ready
|
|
221
|
-
</p>
|
|
222
|
-
<p>Protect your account with a fresh password and keep notifications on.</p>
|
|
223
|
-
</div>
|
|
224
|
-
<Button
|
|
225
|
-
variant="primary"
|
|
226
|
-
size="md"
|
|
227
|
-
className="mt-4 w-full"
|
|
228
|
-
onClick={() => router.push(buildPath('/account/change-password'))}
|
|
229
|
-
>
|
|
230
|
-
Change password
|
|
231
|
-
</Button>
|
|
232
|
-
</div>
|
|
233
|
-
</div>
|
|
234
|
-
</section>
|
|
235
|
-
</motion.div>
|
|
108
|
+
{/* Tab Navigation */}
|
|
109
|
+
<TabNavigation tabs={tabs} activeTab={activeTab} onTabChange={setActiveTab} />
|
|
236
110
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
className="space-y-4 h-full"
|
|
242
|
-
>
|
|
243
|
-
<section className="rounded-3xl border border-slate-200 bg-white p-6 shadow-sm min-h-[420px] h-full flex flex-col">
|
|
244
|
-
<div className="flex items-center justify-between">
|
|
245
|
-
<div>
|
|
246
|
-
<p className="text-xs font-semibold uppercase tracking-[0.3em] text-slate-400">
|
|
247
|
-
Quick links
|
|
248
|
-
</p>
|
|
249
|
-
<h3 className="mt-1 text-lg font-semibold text-slate-900">Next steps</h3>
|
|
250
|
-
</div>
|
|
251
|
-
<Heart className="h-5 w-5 text-primary-500" />
|
|
252
|
-
</div>
|
|
253
|
-
<div className="mt-5 grid gap-3">
|
|
254
|
-
{quickLinks.map((item) => (
|
|
255
|
-
<Link
|
|
256
|
-
key={item.href}
|
|
257
|
-
href={item.href}
|
|
258
|
-
className="group relative flex items-start gap-3 rounded-2xl border border-slate-200 bg-slate-50/70 p-4 transition duration-200 hover:-translate-y-0.5 hover:border-primary-200 hover:bg-white hover:shadow-md"
|
|
259
|
-
>
|
|
260
|
-
<span className="flex h-11 w-11 items-center justify-center rounded-xl bg-white text-primary-600 shadow-sm group-hover:bg-primary-600 group-hover:text-white">
|
|
261
|
-
<item.icon className="h-5 w-5" />
|
|
262
|
-
</span>
|
|
263
|
-
<div className="flex-1">
|
|
264
|
-
<p className="flex items-center gap-2 text-base font-semibold text-slate-900 group-hover:text-primary-700">
|
|
265
|
-
{item.label}
|
|
266
|
-
<ArrowRight className="h-4 w-4 opacity-0 transition group-hover:opacity-100" />
|
|
267
|
-
</p>
|
|
268
|
-
<p className="text-sm text-slate-500">{item.description}</p>
|
|
269
|
-
</div>
|
|
270
|
-
</Link>
|
|
271
|
-
))}
|
|
272
|
-
</div>
|
|
273
|
-
</section>
|
|
274
|
-
</motion.aside>
|
|
111
|
+
{/* Tab Content */}
|
|
112
|
+
<div className="container mx-auto max-w-7xl">
|
|
113
|
+
<div className="rounded-2xl shadow-sm">
|
|
114
|
+
{renderTabContent()}
|
|
275
115
|
</div>
|
|
276
116
|
</div>
|
|
277
117
|
</div>
|
|
@@ -921,7 +921,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
|
|
|
921
921
|
|
|
922
922
|
{/* Shop by Category Section */}
|
|
923
923
|
<section className="py-8 bg-white">
|
|
924
|
-
<div className="
|
|
924
|
+
<div className="container mx-auto px-4">
|
|
925
925
|
<h2 className="text-2xl md:text-3xl font-['Poppins',sans-serif] font-semibold text-secondary mb-6">
|
|
926
926
|
Shop by Category
|
|
927
927
|
</h2>
|