hey-pharmacist-ecommerce 1.1.2 → 1.1.4
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 +9 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +810 -703
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +616 -510
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/Footer.tsx +17 -15
- package/src/components/Header.tsx +14 -12
- package/src/components/OrderCard.tsx +3 -1
- package/src/components/ProductCard.tsx +3 -1
- package/src/index.ts +1 -0
- package/src/lib/api-adapter/config.ts +8 -5
- package/src/providers/AuthProvider.tsx +19 -5
- package/src/providers/BasePathProvider.tsx +36 -0
- package/src/providers/EcommerceProvider.tsx +13 -9
- package/src/providers/FavoritesProvider.tsx +12 -2
- package/src/screens/CartScreen.tsx +5 -3
- package/src/screens/CategoriesScreen.tsx +4 -2
- package/src/screens/CheckoutScreen.tsx +6 -4
- package/src/screens/CurrentOrdersScreen.tsx +4 -2
- package/src/screens/HomeScreen.tsx +8 -6
- package/src/screens/LoginScreen.tsx +3 -1
- package/src/screens/OrdersScreen.tsx +3 -1
- package/src/screens/ProductDetailScreen.tsx +5 -3
- package/src/screens/ProfileScreen.tsx +10 -8
- package/src/screens/RegisterScreen.tsx +3 -1
- package/src/screens/SearchResultsScreen.tsx +4 -2
- package/src/screens/ShopScreen.tsx +7 -5
- package/src/screens/WishlistScreen.tsx +7 -5
|
@@ -11,6 +11,7 @@ import { useOrders } from '@/hooks/useOrders';
|
|
|
11
11
|
import { FilterChips } from '@/components/FilterChips';
|
|
12
12
|
import { useRouter } from 'next/navigation';
|
|
13
13
|
import { ManualOrderDTOOrderStatusEnum, PaymentPaymentStatusEnum } from '@/lib/Apis';
|
|
14
|
+
import { useBasePath } from '@/providers/BasePathProvider';
|
|
14
15
|
|
|
15
16
|
const STATUS_FILTERS = ['All', ...Object.values(ManualOrderDTOOrderStatusEnum)];
|
|
16
17
|
const PAYMENT_FILTERS = ['All', ...Object.values(PaymentPaymentStatusEnum)];
|
|
@@ -19,6 +20,7 @@ type PaymentFilterType = (typeof PAYMENT_FILTERS)[number];
|
|
|
19
20
|
|
|
20
21
|
export function OrdersScreen() {
|
|
21
22
|
const router = useRouter();
|
|
23
|
+
const { buildPath } = useBasePath();
|
|
22
24
|
const [page, setPage] = useState(1);
|
|
23
25
|
const [selectedFilter, setSelectedFilter] = useState<StatusFilterType>('All');
|
|
24
26
|
const [selectedPaymentFilter, setSelectedPaymentFilter] = useState<PaymentFilterType>('All');
|
|
@@ -160,7 +162,7 @@ export function OrdersScreen() {
|
|
|
160
162
|
title="No orders found for these filters"
|
|
161
163
|
description="Adjust the status or payment filters, or browse the shop for new essentials."
|
|
162
164
|
actionLabel="Shop products"
|
|
163
|
-
onAction={() => router.push('/shop')}
|
|
165
|
+
onAction={() => router.push(buildPath('/shop'))}
|
|
164
166
|
/>
|
|
165
167
|
)}
|
|
166
168
|
</div>
|
|
@@ -32,6 +32,7 @@ import { ProductVariantsApi } from '@/lib/Apis/apis/product-variants-api';
|
|
|
32
32
|
import { AXIOS_CONFIG } from '@/lib/Apis/wrapper';
|
|
33
33
|
import { useWishlist } from '@/providers/WishlistProvider';
|
|
34
34
|
import { ProductsApi, ProductVariant, ProductVariantInventoryStatusEnum } from '@/lib/Apis';
|
|
35
|
+
import { useBasePath } from '@/providers/BasePathProvider';
|
|
35
36
|
|
|
36
37
|
const safeFormatDate = (date?: Date | string, format: 'long' | 'short' = 'long'): string => {
|
|
37
38
|
if (!date) return 'N/A';
|
|
@@ -51,6 +52,7 @@ interface ProductDetailScreenProps {
|
|
|
51
52
|
export function ProductDetailScreen({ productId }: ProductDetailScreenProps) {
|
|
52
53
|
// Hooks and state at the top level
|
|
53
54
|
const router = useRouter();
|
|
55
|
+
const { buildPath } = useBasePath();
|
|
54
56
|
const { product: productData, isLoading } = useProduct(productId);
|
|
55
57
|
const { addToCart } = useCart();
|
|
56
58
|
|
|
@@ -330,17 +332,17 @@ export function ProductDetailScreen({ productId }: ProductDetailScreenProps) {
|
|
|
330
332
|
<Button
|
|
331
333
|
variant="ghost"
|
|
332
334
|
className="text-white hover:bg-white/10"
|
|
333
|
-
onClick={() => router.push('/shop')}
|
|
335
|
+
onClick={() => router.push(buildPath('/shop'))}
|
|
334
336
|
>
|
|
335
337
|
<ArrowLeft className="h-5 w-5" />
|
|
336
338
|
Continue shopping
|
|
337
339
|
</Button>
|
|
338
340
|
<div className="hidden items-center gap-3 text-sm text-white/80 md:flex">
|
|
339
|
-
<Link href=
|
|
341
|
+
<Link href={buildPath('/')} className="transition hover:text-white">
|
|
340
342
|
Home
|
|
341
343
|
</Link>
|
|
342
344
|
<ChevronRight className="h-4 w-4" />
|
|
343
|
-
<Link href=
|
|
345
|
+
<Link href={buildPath('/shop')} className="transition hover:text-white">
|
|
344
346
|
Shop
|
|
345
347
|
</Link>
|
|
346
348
|
<ChevronRight className="h-4 w-4" />
|
|
@@ -24,6 +24,7 @@ import { Input } from '@/components/ui/Input';
|
|
|
24
24
|
import { useAuth } from '@/providers/AuthProvider';
|
|
25
25
|
import { toast } from 'sonner';
|
|
26
26
|
import { getInitials } from '@/lib/utils/format';
|
|
27
|
+
import { useBasePath } from '@/providers/BasePathProvider';
|
|
27
28
|
|
|
28
29
|
const profileSchema = z.object({
|
|
29
30
|
firstName: z.string().min(2, 'First name is required'),
|
|
@@ -37,6 +38,7 @@ type ProfileFormData = z.infer<typeof profileSchema>;
|
|
|
37
38
|
export function ProfileScreen() {
|
|
38
39
|
const router = useRouter();
|
|
39
40
|
const { user, updateUser, logout } = useAuth();
|
|
41
|
+
const { buildPath } = useBasePath();
|
|
40
42
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
41
43
|
|
|
42
44
|
const {
|
|
@@ -68,11 +70,11 @@ export function ProfileScreen() {
|
|
|
68
70
|
const handleLogout = async () => {
|
|
69
71
|
await logout();
|
|
70
72
|
toast.success('Logged out successfully');
|
|
71
|
-
router.push('/');
|
|
73
|
+
router.push(buildPath('/'));
|
|
72
74
|
};
|
|
73
75
|
|
|
74
76
|
if (!user) {
|
|
75
|
-
router.push('/login');
|
|
77
|
+
router.push(buildPath('/login'));
|
|
76
78
|
return null;
|
|
77
79
|
}
|
|
78
80
|
|
|
@@ -81,19 +83,19 @@ export function ProfileScreen() {
|
|
|
81
83
|
icon: Package,
|
|
82
84
|
label: 'Order history',
|
|
83
85
|
description: 'Track shipments and download invoices',
|
|
84
|
-
href: '/orders',
|
|
86
|
+
href: buildPath('/orders'),
|
|
85
87
|
},
|
|
86
88
|
{
|
|
87
89
|
icon: Heart,
|
|
88
90
|
label: 'Wishlist',
|
|
89
91
|
description: 'Curate go-to remedies and favorites',
|
|
90
|
-
href: '/wishlist',
|
|
92
|
+
href: buildPath('/wishlist'),
|
|
91
93
|
},
|
|
92
94
|
{
|
|
93
95
|
icon: MapPin,
|
|
94
96
|
label: 'Delivery addresses',
|
|
95
97
|
description: 'Manage saved delivery locations',
|
|
96
|
-
href: '/account/addresses',
|
|
98
|
+
href: buildPath('/account/addresses'),
|
|
97
99
|
},
|
|
98
100
|
];
|
|
99
101
|
|
|
@@ -134,7 +136,7 @@ export function ProfileScreen() {
|
|
|
134
136
|
<Button
|
|
135
137
|
variant="ghost"
|
|
136
138
|
className="text-white hover:bg-white/20"
|
|
137
|
-
onClick={() => router.push('/account/change-password')}
|
|
139
|
+
onClick={() => router.push(buildPath('/account/change-password'))}
|
|
138
140
|
>
|
|
139
141
|
Change password
|
|
140
142
|
</Button>
|
|
@@ -211,7 +213,7 @@ export function ProfileScreen() {
|
|
|
211
213
|
type="button"
|
|
212
214
|
variant="outline"
|
|
213
215
|
size="lg"
|
|
214
|
-
onClick={() => router.push('/orders')}
|
|
216
|
+
onClick={() => router.push(buildPath('/orders'))}
|
|
215
217
|
>
|
|
216
218
|
View recent orders
|
|
217
219
|
</Button>
|
|
@@ -257,7 +259,7 @@ export function ProfileScreen() {
|
|
|
257
259
|
<Button
|
|
258
260
|
variant="outline"
|
|
259
261
|
className="mt-4 w-full"
|
|
260
|
-
onClick={() => router.push('/account/preferences')}
|
|
262
|
+
onClick={() => router.push(buildPath('/account/preferences'))}
|
|
261
263
|
>
|
|
262
264
|
Manage preferences
|
|
263
265
|
</Button>
|
|
@@ -21,6 +21,7 @@ import { Button } from '@/components/ui/Button';
|
|
|
21
21
|
import { useAuth } from '@/providers/AuthProvider';
|
|
22
22
|
import { toast } from 'sonner';
|
|
23
23
|
import { CreateUserDtoCustomerTypeEnum, CreateUserDtoRoleEnum } from '@/lib/Apis/models';
|
|
24
|
+
import { useBasePath } from '@/providers/BasePathProvider';
|
|
24
25
|
|
|
25
26
|
const registerSchema = z
|
|
26
27
|
.object({
|
|
@@ -47,6 +48,7 @@ const BENEFITS = [
|
|
|
47
48
|
export function RegisterScreen() {
|
|
48
49
|
const router = useRouter();
|
|
49
50
|
const { register: registerUser } = useAuth();
|
|
51
|
+
const { buildPath } = useBasePath();
|
|
50
52
|
const [showPassword, setShowPassword] = useState(false);
|
|
51
53
|
const [showConfirmPassword, setShowConfirmPassword] = useState(false);
|
|
52
54
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
@@ -70,7 +72,7 @@ export function RegisterScreen() {
|
|
|
70
72
|
role: CreateUserDtoRoleEnum.User,
|
|
71
73
|
});
|
|
72
74
|
toast.success('Account created successfully!');
|
|
73
|
-
router.push('/');
|
|
75
|
+
router.push(buildPath('/'));
|
|
74
76
|
} catch (error: any) {
|
|
75
77
|
toast.error(error.response?.data?.message || 'Failed to create account');
|
|
76
78
|
} finally {
|
|
@@ -12,9 +12,11 @@ import Link from 'next/link';
|
|
|
12
12
|
import { AXIOS_CONFIG } from '@/lib/Apis/wrapper';
|
|
13
13
|
import { useWishlist } from '@/providers/WishlistProvider';
|
|
14
14
|
import { useRouter } from 'next/navigation';
|
|
15
|
+
import { useBasePath } from '@/providers/BasePathProvider';
|
|
15
16
|
|
|
16
17
|
export default function SearchPage() {
|
|
17
|
-
|
|
18
|
+
const router = useRouter();
|
|
19
|
+
const { buildPath } = useBasePath();
|
|
18
20
|
const searchParams = useSearchParams();
|
|
19
21
|
const searchQuery = searchParams.get('q') || '';
|
|
20
22
|
const [products, setProducts] = useState<ExtendedProductDTO[]>([]);
|
|
@@ -136,7 +138,7 @@ export default function SearchPage() {
|
|
|
136
138
|
<ProductCard
|
|
137
139
|
product={product}
|
|
138
140
|
isFavorited={isInWishlist(product.id)}
|
|
139
|
-
onClickProduct={(p) => router.push(`/products/${p.id}`)}
|
|
141
|
+
onClickProduct={(p) => router.push(buildPath(`/products/${p.id}`))}
|
|
140
142
|
/>
|
|
141
143
|
))}
|
|
142
144
|
</div>
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from 'lucide-react';
|
|
24
24
|
import Image from 'next/image';
|
|
25
25
|
import { useRouter } from 'next/navigation';
|
|
26
|
+
import { useBasePath } from '@/providers/BasePathProvider';
|
|
26
27
|
import { ProductCard } from '@/components/ProductCard';
|
|
27
28
|
import { ProductCardSkeleton } from '@/components/ui/Skeleton';
|
|
28
29
|
import { EmptyState } from '@/components/EmptyState';
|
|
@@ -42,6 +43,7 @@ interface ShopScreenProps {
|
|
|
42
43
|
|
|
43
44
|
export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProps) {
|
|
44
45
|
const router = useRouter();
|
|
46
|
+
const { buildPath } = useBasePath();
|
|
45
47
|
const [filters, setFilters] = useState<ProductFilters>(initialFilters);
|
|
46
48
|
const [page, setPage] = useState(1);
|
|
47
49
|
const [showFilters, setShowFilters] = useState(false);
|
|
@@ -63,7 +65,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
|
|
|
63
65
|
e.preventDefault();
|
|
64
66
|
if (searchQuery.trim()) {
|
|
65
67
|
setIsSearching(true);
|
|
66
|
-
router.push(`/search?q=${encodeURIComponent(searchQuery.trim())}`);
|
|
68
|
+
router.push(buildPath(`/search?q=${encodeURIComponent(searchQuery.trim())}`));
|
|
67
69
|
}
|
|
68
70
|
};
|
|
69
71
|
|
|
@@ -77,7 +79,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
|
|
|
77
79
|
if (e.key === 'Enter' && searchQuery.trim()) {
|
|
78
80
|
e.preventDefault();
|
|
79
81
|
setIsSearching(true);
|
|
80
|
-
router.push(`/search?q=${encodeURIComponent(searchQuery.trim())}`);
|
|
82
|
+
router.push(buildPath(`/search?q=${encodeURIComponent(searchQuery.trim())}`));
|
|
81
83
|
}
|
|
82
84
|
};
|
|
83
85
|
|
|
@@ -1026,7 +1028,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
|
|
|
1026
1028
|
product={product}
|
|
1027
1029
|
onClickProduct={(item) => {
|
|
1028
1030
|
const productData = encodeURIComponent(JSON.stringify(item));
|
|
1029
|
-
router.push(`/products/${item.id}?product=${productData}`);
|
|
1031
|
+
router.push(buildPath(`/products/${item.id}?product=${productData}`));
|
|
1030
1032
|
}}
|
|
1031
1033
|
/>
|
|
1032
1034
|
</div>
|
|
@@ -1049,7 +1051,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
|
|
|
1049
1051
|
key={product.id}
|
|
1050
1052
|
whileHover={{ y: -4 }}
|
|
1051
1053
|
className="group flex cursor-pointer flex-col gap-6 rounded-2xl border border-gray-100 bg-white p-5 shadow-sm transition hover:shadow-xl md:flex-row md:items-start"
|
|
1052
|
-
onClick={() => router.push(`/products/${product.id}`)}
|
|
1054
|
+
onClick={() => router.push(buildPath(`/products/${product.id}`))}
|
|
1053
1055
|
>
|
|
1054
1056
|
<div className="relative h-48 w-full overflow-hidden rounded-2xl bg-gray-100 md:h-40 md:w-40">
|
|
1055
1057
|
<Image
|
|
@@ -1111,7 +1113,7 @@ export function ShopScreen({ initialFilters = {}, categoryName }: ShopScreenProp
|
|
|
1111
1113
|
size="sm"
|
|
1112
1114
|
onClick={(event) => {
|
|
1113
1115
|
event.stopPropagation();
|
|
1114
|
-
router.push(`/products/${product._id}`);
|
|
1116
|
+
router.push(buildPath(`/products/${product._id}`));
|
|
1115
1117
|
}}
|
|
1116
1118
|
>
|
|
1117
1119
|
View product
|
|
@@ -23,6 +23,7 @@ import { useWishlistProducts } from '@/hooks/useWishlistProducts';
|
|
|
23
23
|
import Image from 'next/image';
|
|
24
24
|
import { formatPrice } from '@/lib/utils/format';
|
|
25
25
|
import { ExtendedProductDTO } from '@/lib/Apis';
|
|
26
|
+
import { useBasePath } from '@/providers/BasePathProvider';
|
|
26
27
|
|
|
27
28
|
type SortOption = 'featured' | 'price-low' | 'price-high' | 'name' | 'availability';
|
|
28
29
|
|
|
@@ -45,6 +46,7 @@ interface InsightCardProps {
|
|
|
45
46
|
|
|
46
47
|
export default function WishlistScreen() {
|
|
47
48
|
const router = useRouter();
|
|
49
|
+
const { buildPath } = useBasePath();
|
|
48
50
|
const { isAuthenticated } = useAuth() || {};
|
|
49
51
|
const {
|
|
50
52
|
products: wishlistItems,
|
|
@@ -181,7 +183,7 @@ export default function WishlistScreen() {
|
|
|
181
183
|
<p className="mt-3 text-slate-500">
|
|
182
184
|
Create your curated shelf of products and we'll keep them ready whenever you return.
|
|
183
185
|
</p>
|
|
184
|
-
<Button className="mt-6" onClick={() => router.push('/login')}>
|
|
186
|
+
<Button className="mt-6" onClick={() => router.push(buildPath('/login'))}>
|
|
185
187
|
Sign In
|
|
186
188
|
</Button>
|
|
187
189
|
</div>
|
|
@@ -285,8 +287,8 @@ export default function WishlistScreen() {
|
|
|
285
287
|
Bookmark pharmacy essentials, supplements, or skincare picks and we'll keep them safe until you're ready to checkout.
|
|
286
288
|
</p>
|
|
287
289
|
<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
|
+
<Button onClick={() => router.push(buildPath('/shop'))}>Discover products</Button>
|
|
291
|
+
<Button variant="outline" onClick={() => router.push(buildPath('/categories'))}>
|
|
290
292
|
Browse categories
|
|
291
293
|
</Button>
|
|
292
294
|
</div>
|
|
@@ -314,7 +316,7 @@ export default function WishlistScreen() {
|
|
|
314
316
|
>
|
|
315
317
|
<ProductCard
|
|
316
318
|
product={product as ExtendedProductDTO}
|
|
317
|
-
|
|
319
|
+
onClickProduct={(p) => router.push(buildPath(`/products/${p.id}`))}
|
|
318
320
|
onFavorite={() => handleRemoveFromWishlist(product.id)}
|
|
319
321
|
isFavorited
|
|
320
322
|
/>
|
|
@@ -379,7 +381,7 @@ export default function WishlistScreen() {
|
|
|
379
381
|
<div className="flex flex-wrap gap-2">
|
|
380
382
|
<Button
|
|
381
383
|
size="sm"
|
|
382
|
-
onClick={() => router.push(`/products/${product.id}`)}
|
|
384
|
+
onClick={() => router.push(buildPath(`/products/${product.id}`))}
|
|
383
385
|
>
|
|
384
386
|
View details
|
|
385
387
|
</Button>
|